Skip to content
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

Download models in the background #1669

Closed
wants to merge 32 commits into from
Closed
Show file tree
Hide file tree
Changes from 1 commit
Commits
Show all changes
32 commits
Select commit Hold shift + click to select a range
717f1c4
Download models in the background
Aug 26, 2022
b6952a7
Added ability to disable parallel download
Aug 30, 2022
7fdb8aa
Merge branch 'gz-sim7' into nkoenig_download_parallel
Aug 30, 2022
7dc0b5b
fix help message
Aug 30, 2022
ce26ff7
cleanup
Aug 30, 2022
28280e5
Merge branch 'gz-sim7' into nkoenig_download_parallel
Oct 6, 2022
8ada77a
merged with gz-sim7
Oct 20, 2022
594a509
unblock GUI while waiting for assets
Oct 24, 2022
25bb933
Merge branch 'nkoenig_download_parallel' of github.com:gazebosim/gz-s…
Oct 24, 2022
3e3a362
Resource spawner thread
Oct 25, 2022
60c43b1
Support reset
Oct 25, 2022
d13f72b
working on updates
nkoenig Jun 22, 2023
2a99d60
merged with gz-sim7
nkoenig Jun 22, 2023
b206fe6
fixed build
nkoenig Jun 22, 2023
7d016b0
All tests pass!
nkoenig Aug 16, 2023
17d2763
Cleanup and codechecker
nkoenig Aug 18, 2023
ffdc26a
Merge branch 'gz-sim7' into nkoenig_download_parallel
nkoenig Aug 18, 2023
f79d8ce
More cleanup
nkoenig Aug 21, 2023
9bc310b
Increase UNIT_Server_TEST timeout
nkoenig Aug 23, 2023
85e13d6
Merged with gz-sim7
nkoenig Nov 2, 2023
41a1101
Merge branch 'gz-sim7' into nkoenig_download_parallel
nkoenig Nov 6, 2023
c299c98
Merge branch 'gz-sim7' into nkoenig_download_parallel
nkoenig Feb 14, 2024
ec23a22
Output errors, still create entities
nkoenig Mar 6, 2024
cf5f36a
Fix whitespace
nkoenig Mar 11, 2024
64d4244
Revert comments
nkoenig May 31, 2024
2ddc8cc
Merge branch 'gz-sim7' into nkoenig_download_parallel
nkoenig May 31, 2024
e2db6e3
Revert a few topic name generations
nkoenig Jun 3, 2024
bf259f5
Merge branch 'gz-sim7' into nkoenig_download_parallel
nkoenig Jun 3, 2024
656f6d6
Merged with gz-sim7
nkoenig Jun 26, 2024
7dd2db0
merged with gz-sim7
nkoenig Jul 3, 2024
69c2384
Merge branch 'gz-sim7' into nkoenig_download_parallel
nkoenig Aug 12, 2024
0be35e6
Simplify diff
nkoenig Aug 12, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 12 additions & 0 deletions include/gz/sim/ServerConfig.hh
Original file line number Diff line number Diff line change
Expand Up @@ -445,6 +445,18 @@ namespace gz
public: const std::chrono::time_point<std::chrono::system_clock> &
Timestamp() const;

/// \brief Set whether asset download should block simulation start.
/// The default value is true.
/// \param[in] _set True to wait while assets download. False will
/// download assets in a background thread.
public: void SetWaitForAssets(bool _set);

/// \brief Get whether asset download should block simulation start.
/// The default value is true.
/// \return True if simulation should wait while assets download. False
/// indicates assets should be downloaded in a separate thread.
public: bool WaitForAssets() const;

/// \brief Get the type of source
/// \return The source type.
public: SourceType Source() const;
Expand Down
2 changes: 1 addition & 1 deletion src/Conversions.cc
Original file line number Diff line number Diff line change
Expand Up @@ -257,7 +257,7 @@ msgs::Geometry gz::sim::convert(const sdf::Geometry &_in)
}
}
}
else
else if (_in.Type() != sdf::GeometryType::EMPTY)
{
gzerr << "Geometry type [" << static_cast<int>(_in.Type())
<< "] not supported" << std::endl;
Expand Down
136 changes: 78 additions & 58 deletions src/Server.cc
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,9 @@ Server::Server(const ServerConfig &_config)
config.SetCacheLocation(_config.ResourceCache());
this->dataPtr->fuelClient = std::make_unique<fuel_tools::FuelClient>(config);

// Turn on/off downloads.
this->dataPtr->enableDownload = _config.WaitForAssets();

// Configure SDF to fetch assets from Gazebo Fuel.
sdf::setFindCallback(std::bind(&ServerPrivate::FetchResource,
this->dataPtr.get(), std::placeholders::_1));
Expand All @@ -57,16 +60,18 @@ Server::Server(const ServerConfig &_config)

// Ignore the sdf::Errors returned by this function. The errors will be
// displayed later in the downloadThread.
this->dataPtr->LoadSdfRootHelper(_config, this->dataPtr->sdfRoot, outputMsgs);
sdf::Errors errors = this->dataPtr->LoadSdfRootHelper(_config,
this->dataPtr->sdfRoot, outputMsgs);
gzmsg << outputMsgs;

// Remove all the models from the primary sdfRoot object so that they can
// be downloaded and added to simulation in the background.
for (uint64_t i = 0; i < this->dataPtr->sdfRoot.WorldCount(); ++i)
if (_config.WaitForAssets())
{
this->dataPtr->sdfRoot.WorldByIndex(i)->ClearModels();
this->dataPtr->sdfRoot.WorldByIndex(i)->ClearActors();
this->dataPtr->sdfRoot.WorldByIndex(i)->ClearLights();
if (!errors.empty())
{
for (auto &err : errors)
gzerr << err << "\n";
return;
}
}

// Add record plugin
Expand All @@ -77,6 +82,72 @@ Server::Server(const ServerConfig &_config)

this->dataPtr->CreateEntities();

if (!_config.WaitForAssets())
{
// Remove all the models from the primary sdfRoot object so that they can
// be downloaded and added to simulation in the background.
for (uint64_t i = 0; i < this->dataPtr->sdfRoot.WorldCount(); ++i)
{
this->dataPtr->sdfRoot.WorldByIndex(i)->ClearModels();
this->dataPtr->sdfRoot.WorldByIndex(i)->ClearActors();
this->dataPtr->sdfRoot.WorldByIndex(i)->ClearLights();
}

// Turn on downloads.
this->dataPtr->enableDownload = true;

// Force each simulation runner to remain paused until the downloads are
// complete.
for (auto &runner : this->dataPtr->simRunners)
{
runner->SetForcedPause(true);
}

// Download models in a separate thread.
this->dataPtr->downloadThread = std::thread([&]()
{
// Reload the SDF root, which will cause the models to download.
sdf::Root localRoot;
std::string ignoreMessages;
sdf::Errors localErrors = this->dataPtr->LoadSdfRootHelper(_config,
localRoot, ignoreMessages);

// Output any errors.
if (!localErrors.empty())
{
for (auto &err : localErrors)
gzerr << err << "\n";
}
else
{
// Add the models back into the worlds.
for (auto &runner : this->dataPtr->simRunners)
{
std::string worldName = runner->WorldSdf().Name();
const sdf::World *world = localRoot.WorldByName(worldName);
if (world)
{
for (uint64_t i = 0; i < world->ActorCount(); ++i)
runner->CreateEntity(*world->ActorByIndex(i));
for (uint64_t i = 0; i < world->LightCount(); ++i)
runner->CreateEntity(*world->LightByIndex(i));
for (uint64_t i = 0; i < world->ModelCount(); ++i)
runner->CreateEntity(*world->ModelByIndex(i));
}
else
{
gzerr << "Unable to find world with name[" << worldName << "]. "
<< "Downloaded models may not appear.\n";
}

// Allow the runner to resume normal operations.
runner->SetForcedPause(false);
}
}
});
}


// Set the desired update period, this will override the desired RTF given in
// the world file which was parsed by CreateEntities.
if (_config.UpdatePeriod())
Expand All @@ -87,58 +158,7 @@ Server::Server(const ServerConfig &_config)
// Establish publishers and subscribers.
this->dataPtr->SetupTransport();

// Turn on downloads.
this->dataPtr->enableDownload = true;

// Force each simulation runner to remain paused until the downloads are
// complete.
for (auto &runner : this->dataPtr->simRunners)
{
runner->SetForcedPause(true);
}

// Download models in a separate thread.
this->dataPtr->downloadThread = std::thread([&]()
{
// Reload the SDF root, which will cause the models to download.
sdf::Root localRoot;
std::string ignoreMessages;
sdf::Errors errors = this->dataPtr->LoadSdfRootHelper(_config,
localRoot, ignoreMessages);

// Output any errors.
if (!errors.empty())
{
for (auto &err : errors)
gzerr << err << "\n";
}
else
{
// Add the models back into the worlds.
for (auto &runner : this->dataPtr->simRunners)
{
std::string worldName = runner->WorldSdf().Name();
const sdf::World *world = localRoot.WorldByName(worldName);
if (world)
{
for (uint64_t i = 0; i < world->ActorCount(); ++i)
runner->CreateEntity(*world->ActorByIndex(i));
for (uint64_t i = 0; i < world->LightCount(); ++i)
runner->CreateEntity(*world->LightByIndex(i));
for (uint64_t i = 0; i < world->ModelCount(); ++i)
runner->CreateEntity(*world->ModelByIndex(i));
}
else
{
gzerr << "Unable to find world with name[" << worldName << "]. "
<< "Downloaded models may not appear.\n";
}

// Allow the runner to resume normal operations.
runner->SetForcedPause(false);
}
}
});
}

/////////////////////////////////////////////////
Expand Down
15 changes: 15 additions & 0 deletions src/ServerConfig.cc
Original file line number Diff line number Diff line change
Expand Up @@ -333,6 +333,9 @@ class gz::sim::ServerConfigPrivate

/// \brief Type of source used.
public: ServerConfig::SourceType source{ServerConfig::SourceType::kNone};

/// \brief True to block while simulation assets download.
public: bool waitForAssets = true;
};

//////////////////////////////////////////////////
Expand Down Expand Up @@ -719,6 +722,18 @@ ServerConfig::Timestamp() const
return this->dataPtr->timestamp;
}

/////////////////////////////////////////////////
void ServerConfig::SetWaitForAssets(bool _set)
{
this->dataPtr->waitForAssets = _set;
}

/////////////////////////////////////////////////
bool ServerConfig::WaitForAssets() const
{
return this->dataPtr->waitForAssets;
}

/////////////////////////////////////////////////
void ServerConfig::AddLogRecordTopic(const std::string &_topic)
{
Expand Down
3 changes: 2 additions & 1 deletion src/SimulationRunner.hh
Original file line number Diff line number Diff line change
Expand Up @@ -568,14 +568,15 @@ namespace gz
/// background. The simulation runner must remain paused while this
/// takes place. This flag can be used to make sure simulation stays
/// paused.
private: bool forcedPause{true};
private: bool forcedPause{false};

/// \brief During a forced pause, the user may request that simulation
/// should run. This flag will capture that request, and then be used
/// when the forced pause ends.
private: bool requestedPause{true};

private: bool resetInitiated{false};

friend class LevelManager;
};
}
Expand Down
16 changes: 12 additions & 4 deletions src/cmd/cmdsim.rb.in
Original file line number Diff line number Diff line change
Expand Up @@ -109,6 +109,8 @@ COMMANDS = { 'sim' =>
"\n"\
" --headless-rendering Run rendering in headless mode \n"\
"\n"\
" --parallel-download Download assets in a background thread. \n"\
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm getting this error

Traceback (most recent call last):
	2: from /home/ahcorde/gz_garden/install/bin/gz:308:in `<main>'
	1: from /home/ahcorde/gz_garden/install/lib/ruby/gz/cmdsim7.rb:343:in `execute'
/home/ahcorde/gz_garden/install/lib/ruby/gz/cmdsim7.rb:329:in `parse': invalid option: --parallel-download (OptionParser::InvalidOption)
Suggested change
" --parallel-download Download assets in a background thread. \n"\
" --wait-for-assets Download assets in a background thread. \n"\

"\n"\
" -r Run simulation on start. \n"\
"\n"\
" -s Run only the server (headless mode). This \n"\
Expand Down Expand Up @@ -224,7 +226,8 @@ class Cmd
'render_engine_gui' => '',
'render_engine_server' => '',
'wait_gui' => 1,
'headless-rendering' => 0
'headless-rendering' => 0,
'wait-for-assets' => 0
}

usage = COMMANDS[args[0]]
Expand Down Expand Up @@ -304,6 +307,9 @@ class Cmd
opts.on('--headless-rendering') do
options['headless-rendering'] = 1
end
opts.on('--wait-for-assets') do
options['wait-for-assets'] = 1
end
opts.on('--render-engine-gui [arg]', String) do |g|
options['render_engine_gui'] = g
end
Expand Down Expand Up @@ -455,7 +461,7 @@ Please use [GZ_SIM_RESOURCE_PATH] instead."
const char *, int, int, const char *,
int, int, int, const char *, const char *,
const char *, const char *, const char *,
const char *, int, int)'
const char *, int, int, int)'

# Import the runGui function
Importer.extern 'int runGui(const char *, const char *, int, const char *)'
Expand Down Expand Up @@ -490,7 +496,8 @@ See https://github.com/gazebosim/gz-sim/issues/44 for more info."
options['render_engine_server'], options['render_engine_gui'],
options['file'], options['record-topics'].join(':'),
options['wait_gui'],
options['headless-rendering'])
options['headless-rendering'],
options['wait-for-assets'])
end

guiPid = Process.fork do
Expand Down Expand Up @@ -527,7 +534,8 @@ See https://github.com/gazebosim/gz-sim/issues/44 for more info."
options['playback'], options['physics_engine'],
options['render_engine_server'], options['render_engine_gui'],
options['file'], options['record-topics'].join(':'),
options['wait_gui'], options['headless-rendering'])
options['wait_gui'], options['headless-rendering'],
options['parallel-download'])
# Otherwise run the gui
else options['gui']
if plugin.end_with? ".dylib"
Expand Down
4 changes: 3 additions & 1 deletion src/gz.cc
Original file line number Diff line number Diff line change
Expand Up @@ -136,7 +136,7 @@ extern "C" int runServer(const char *_sdfString,
const char *_playback, const char *_physicsEngine,
const char *_renderEngineServer, const char *_renderEngineGui,
const char *_file, const char *_recordTopics, int _waitGui,
int _headless)
int _headless, int _waitForAssets)
{
std::string startingWorldPath{""};
gz::sim::ServerConfig serverConfig;
Expand Down Expand Up @@ -396,6 +396,8 @@ extern "C" int runServer(const char *_sdfString,
serverConfig.SetRenderEngineGui(_renderEngineGui);
}

serverConfig.SetWaitForAssets(!_waitForAssets);

// Create the Gazebo server
gz::sim::Server server(serverConfig);

Expand Down
5 changes: 4 additions & 1 deletion src/gz.hh
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,8 @@ extern "C" const char *worldInstallDir();
/// it receives a world path from GUI.
/// null to record the default topics.
/// \param[in] _headless True if server rendering should run headless
/// \param[in] _waitForAssets True to wait for simulation assets to download
/// before starting simulation.
/// \return 0 if successful, 1 if not.
extern "C" int runServer(const char *_sdfString,
int _iterations, int _run, float _hz, int _levels,
Expand All @@ -65,7 +67,8 @@ extern "C" int runServer(const char *_sdfString,
int _logCompress, const char *_playback,
const char *_physicsEngine, const char *_renderEngineServer,
const char *_renderEngineGui, const char *_file,
const char *_recordTopics, int _waitGui, int _headless);
const char *_recordTopics, int _waitGui, int _headless,
int _waitForAssets);

/// \brief External hook to run simulation GUI.
/// \param[in] _guiConfig Path to Gazebo GUI configuration file.
Expand Down