Skip to content
This repository was archived by the owner on Nov 15, 2023. It is now read-only.

Commit aecc106

Browse files
committed
Implement worker binary embedding and extraction
1 parent 37920a1 commit aecc106

File tree

19 files changed

+105
-139
lines changed

19 files changed

+105
-139
lines changed

Cargo.lock

Lines changed: 2 additions & 2 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

cli/src/cli.rs

Lines changed: 0 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -42,14 +42,6 @@ pub enum Subcommand {
4242
/// Revert the chain to a previous state.
4343
Revert(sc_cli::RevertCmd),
4444

45-
#[allow(missing_docs)]
46-
#[command(name = "prepare-worker", hide = true)]
47-
PvfPrepareWorker(ValidationWorkerCommand),
48-
49-
#[allow(missing_docs)]
50-
#[command(name = "execute-worker", hide = true)]
51-
PvfExecuteWorker(ValidationWorkerCommand),
52-
5345
/// Sub-commands concerned with benchmarking.
5446
/// The pallet benchmarking moved to the `pallet` sub-command.
5547
#[command(subcommand)]
@@ -75,17 +67,6 @@ pub enum Subcommand {
7567
ChainInfo(sc_cli::ChainInfoCmd),
7668
}
7769

78-
#[allow(missing_docs)]
79-
#[derive(Debug, Parser)]
80-
pub struct ValidationWorkerCommand {
81-
/// The path to the validation host's socket.
82-
#[arg(long)]
83-
pub socket_path: String,
84-
/// Calling node implementation version
85-
#[arg(long)]
86-
pub node_impl_version: String,
87-
}
88-
8970
#[allow(missing_docs)]
9071
#[derive(Debug, Parser)]
9172
#[group(skip)]

cli/src/command.rs

Lines changed: 0 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -479,50 +479,6 @@ pub fn run() -> Result<()> {
479479
))
480480
})?)
481481
},
482-
Some(Subcommand::PvfPrepareWorker(cmd)) => {
483-
let mut builder = sc_cli::LoggerBuilder::new("");
484-
builder.with_colors(false);
485-
let _ = builder.init();
486-
487-
#[cfg(target_os = "android")]
488-
{
489-
return Err(sc_cli::Error::Input(
490-
"PVF preparation workers are not supported under this platform".into(),
491-
)
492-
.into())
493-
}
494-
495-
#[cfg(not(target_os = "android"))]
496-
{
497-
polkadot_node_core_pvf_worker::prepare_worker_entrypoint(
498-
&cmd.socket_path,
499-
Some(&cmd.node_impl_version),
500-
);
501-
Ok(())
502-
}
503-
},
504-
Some(Subcommand::PvfExecuteWorker(cmd)) => {
505-
let mut builder = sc_cli::LoggerBuilder::new("");
506-
builder.with_colors(false);
507-
let _ = builder.init();
508-
509-
#[cfg(target_os = "android")]
510-
{
511-
return Err(sc_cli::Error::Input(
512-
"PVF execution workers are not supported under this platform".into(),
513-
)
514-
.into())
515-
}
516-
517-
#[cfg(not(target_os = "android"))]
518-
{
519-
polkadot_node_core_pvf_worker::execute_worker_entrypoint(
520-
&cmd.socket_path,
521-
Some(&cmd.node_impl_version),
522-
);
523-
Ok(())
524-
}
525-
},
526482
Some(Subcommand::Benchmark(cmd)) => {
527483
let runner = cli.create_runner(cmd)?;
528484
let chain_spec = &runner.config().chain_spec;

node/core/candidate-validation/src/lib.rs

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -81,9 +81,11 @@ const DEFAULT_APPROVAL_EXECUTION_TIMEOUT: Duration = Duration::from_secs(12);
8181
pub struct Config {
8282
/// The path where candidate validation can store compiled artifacts for PVFs.
8383
pub artifacts_cache_path: PathBuf,
84+
/// The path to extract the PVF workers to, if `program_path` is `None`.
85+
pub pvf_workers_path: PathBuf,
8486
/// The path to the executable which can be used for spawning PVF compilation & validation
8587
/// workers.
86-
pub program_path: PathBuf,
88+
pub program_path: Option<PathBuf>,
8789
}
8890

8991
/// The candidate validation subsystem.
@@ -117,6 +119,7 @@ impl<Context> CandidateValidationSubsystem {
117119
self.metrics,
118120
self.pvf_metrics,
119121
self.config.artifacts_cache_path,
122+
self.config.pvf_workers_path,
120123
self.config.program_path,
121124
)
122125
.map_err(|e| SubsystemError::with_origin("candidate-validation", e))
@@ -131,10 +134,11 @@ async fn run<Context>(
131134
metrics: Metrics,
132135
pvf_metrics: polkadot_node_core_pvf::Metrics,
133136
cache_path: PathBuf,
134-
program_path: PathBuf,
137+
workers_path: PathBuf,
138+
program_path: Option<PathBuf>,
135139
) -> SubsystemResult<()> {
136140
let (validation_host, task) = polkadot_node_core_pvf::start(
137-
polkadot_node_core_pvf::Config::new(cache_path, program_path),
141+
polkadot_node_core_pvf::Config::new(cache_path, workers_path, program_path),
138142
pvf_metrics,
139143
);
140144
ctx.spawn_blocking("pvf-validation-host", task.boxed())?;

node/core/pvf/src/artifacts.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -304,7 +304,7 @@ mod tests {
304304

305305
#[tokio::test]
306306
async fn artifacts_removes_cache_on_startup() {
307-
let fake_cache_path = crate::worker_common::tmpfile("test-cache").await.unwrap();
307+
let fake_cache_path = crate::worker_intf::tmpfile("test-cache").await.unwrap();
308308
let fake_artifact_path = {
309309
let mut p = fake_cache_path.clone();
310310
p.push("wasmtime_0x1234567890123456789012345678901234567890123456789012345678901234");

node/core/pvf/src/execute/queue.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ use crate::{
2121
artifacts::{ArtifactId, ArtifactPathId},
2222
host::ResultSender,
2323
metrics::Metrics,
24-
worker_common::{IdleWorker, WorkerHandle},
24+
worker_intf::{IdleWorker, WorkerHandle},
2525
InvalidCandidate, ValidationError, LOG_TARGET,
2626
};
2727
use futures::{

node/core/pvf/src/execute/worker_intf.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@
1818
1919
use crate::{
2020
artifacts::ArtifactPathId,
21-
worker_common::{
21+
worker_intf::{
2222
framed_recv, framed_send, path_to_bytes, spawn_with_program_path, IdleWorker, SpawnErr,
2323
WorkerHandle, JOB_TIMEOUT_WALL_CLOCK_FACTOR,
2424
},
@@ -45,7 +45,7 @@ pub async fn spawn(
4545
let (mut idle_worker, worker_handle) = spawn_with_program_path(
4646
"execute",
4747
program_path,
48-
&["--node-impl-version", env!("SUBSTRATE_CLI_IMPL_VERSION")],
48+
&["execute-worker", "--node-impl-version", env!("SUBSTRATE_CLI_IMPL_VERSION")],
4949
spawn_timeout,
5050
)
5151
.await?;

node/core/pvf/src/host.rs

Lines changed: 58 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,7 @@ use std::{
3838
path::{Path, PathBuf},
3939
time::{Duration, SystemTime},
4040
};
41+
use tokio;
4142

4243
/// The time period after which a failed preparation artifact is considered ready to be retried.
4344
/// Note that we will only retry if another request comes in after this cooldown has passed.
@@ -49,6 +50,15 @@ pub const PREPARE_FAILURE_COOLDOWN: Duration = Duration::from_millis(200);
4950
/// The amount of times we will retry failed prepare jobs.
5051
pub const NUM_PREPARE_RETRIES: u32 = 5;
5152

53+
// HACK: Getting the binary locations this way is a bit ugly but seems to work? Should eventually
54+
// use something like wasm-builder: <https://github.com/paritytech/substrate/issues/13982>.
55+
/// The prepare worker binary.
56+
const PREPARE_EXE: &'static [u8] =
57+
include_bytes!(concat!(env!("OUT_DIR"), "/../../../prepare_worker"));
58+
/// The execute worker binary.
59+
const EXECUTE_EXE: &'static [u8] =
60+
include_bytes!(concat!(env!("OUT_DIR"), "/../../../execute_worker"));
61+
5262
/// An alias to not spell the type for the oneshot sender for the PVF execution result.
5363
pub(crate) type ResultSender = oneshot::Sender<Result<ValidationResult, ValidationError>>;
5464

@@ -140,6 +150,8 @@ struct ExecutePvfInputs {
140150
pub struct Config {
141151
/// The root directory where the prepared artifacts can be stored.
142152
pub cache_path: PathBuf,
153+
/// If we are using the embedded worker binaries, the directory where they are extracted to.
154+
pub workers_path: Option<PathBuf>,
143155
/// The path to the program that can be used to spawn the prepare workers.
144156
pub prepare_worker_program_path: PathBuf,
145157
/// The time allotted for a prepare worker to spawn and report to the host.
@@ -159,18 +171,28 @@ pub struct Config {
159171

160172
impl Config {
161173
/// Create a new instance of the configuration.
174+
///
175+
/// The binary at `program_path` will be used if that is `Some`, otherwise the embedded workers
176+
/// will be extracted to `workers_path` and used.
162177
pub fn new(
163178
cache_path: std::path::PathBuf,
164-
prepare_worker_path: std::path::PathBuf,
165-
execute_worker_path: std::path::PathBuf,
179+
workers_path: std::path::PathBuf,
180+
program_path: Option<std::path::PathBuf>,
166181
) -> Self {
167182
// Do not contaminate the other parts of the codebase with the types from `tokio`.
168183
let cache_path = PathBuf::from(cache_path);
169-
let prepare_worker_path = PathBuf::from(prepare_worker_path);
170-
let execute_worker_path = PathBuf::from(execute_worker_path);
184+
185+
let (prepare_worker_path, execute_worker_path, workers_path) =
186+
if let Some(path) = program_path {
187+
let path = PathBuf::from(path);
188+
(path.clone(), path, None)
189+
} else {
190+
(worker_path(&workers_path, "prepare"), worker_path(&workers_path, "execute"), Some(workers_path))
191+
};
171192

172193
Self {
173194
cache_path,
195+
workers_path,
174196
prepare_worker_program_path: prepare_worker_path.clone(),
175197
prepare_worker_spawn_timeout: Duration::from_secs(3),
176198
prepare_workers_soft_max_num: 1,
@@ -222,6 +244,17 @@ pub fn start(config: Config, metrics: Metrics) -> (ValidationHost, impl Future<O
222244
let run_sweeper = sweeper_task(to_sweeper_rx);
223245

224246
let run_host = async move {
247+
if let Some(workers_path) = config.workers_path {
248+
// Make sure that the workers path directory and all its parents are created.
249+
// TODO?: First delete any existing binaries.
250+
// let _ = tokio::fs::remove_dir_all(config.workers_path).await;
251+
let _ = tokio::fs::create_dir_all(workers_path).await;
252+
extract_worker_binaries(
253+
&config.prepare_worker_program_path,
254+
&config.execute_worker_program_path,
255+
)
256+
.await;
257+
}
225258
let artifacts = Artifacts::new(&config.cache_path).await;
226259

227260
run(Inner {
@@ -856,6 +889,27 @@ fn pulse_every(interval: std::time::Duration) -> impl futures::Stream<Item = ()>
856889
.map(|_| ())
857890
}
858891

892+
// TODO: Should we purge unneeded binaries?
893+
/// Extracts the worker binaries embedded in this binary onto disk and return their paths.
894+
async fn extract_worker_binaries(prepare_worker_path: &Path, execute_worker_path: &Path) {
895+
// Skip extraction if the binaries are already present.
896+
if !prepare_worker_path.exists() {
897+
let _ = tokio::fs::write(prepare_worker_path, PREPARE_EXE).await;
898+
}
899+
if !execute_worker_path.exists() {
900+
let _ = tokio::fs::write(execute_worker_path, EXECUTE_EXE).await;
901+
}
902+
}
903+
904+
/// Returns the expected path to this worker given the root of the cache.
905+
///
906+
/// Appends with the version (including the commit) to avoid conflicts with other versions of
907+
/// polkadot running, i.e. in testnets.
908+
fn worker_path(workers_path: &Path, job_kind: &str) -> PathBuf {
909+
let file_name = format!("{}-worker_{}", job_kind, env!("SUBSTRATE_CLI_IMPL_VERSION"));
910+
workers_path.join(file_name)
911+
}
912+
859913
#[cfg(test)]
860914
pub(crate) mod tests {
861915
use super::*;

node/core/pvf/src/lib.rs

Lines changed: 2 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -96,7 +96,7 @@ mod metrics;
9696
mod prepare;
9797
mod priority;
9898
mod pvf;
99-
mod worker_common;
99+
mod worker_intf;
100100

101101
pub use artifacts::CompiledArtifact;
102102
pub use error::{InvalidCandidate, PrepareError, PrepareResult, ValidationError};
@@ -109,11 +109,6 @@ pub use pvf::PvfPrepData;
109109

110110
pub use host::{start, Config, ValidationHost};
111111
pub use metrics::Metrics;
112-
pub use worker_common::{framed_recv, framed_send, JOB_TIMEOUT_WALL_CLOCK_FACTOR};
112+
pub use worker_intf::{framed_recv, framed_send, JOB_TIMEOUT_WALL_CLOCK_FACTOR};
113113

114114
const LOG_TARGET: &str = "parachain::pvf";
115-
116-
#[doc(hidden)]
117-
pub mod testing {
118-
pub use crate::worker_common::{spawn_with_program_path, SpawnErr};
119-
}

node/core/pvf/src/prepare/pool.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ use crate::{
1919
error::{PrepareError, PrepareResult},
2020
metrics::Metrics,
2121
pvf::PvfPrepData,
22-
worker_common::{IdleWorker, WorkerHandle},
22+
worker_intf::{IdleWorker, WorkerHandle},
2323
LOG_TARGET,
2424
};
2525
use always_assert::never;

node/core/pvf/src/prepare/worker_intf.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ use crate::{
2121
metrics::Metrics,
2222
prepare::PrepareStats,
2323
pvf::PvfPrepData,
24-
worker_common::{
24+
worker_intf::{
2525
framed_recv, framed_send, path_to_bytes, spawn_with_program_path, tmpfile_in, IdleWorker,
2626
SpawnErr, WorkerHandle, JOB_TIMEOUT_WALL_CLOCK_FACTOR,
2727
},
File renamed without changes.

node/core/pvf/worker/.cargo/config.toml

Lines changed: 0 additions & 11 deletions
This file was deleted.

node/core/pvf/worker/.cargo/musl-g++

Lines changed: 0 additions & 7 deletions
This file was deleted.

node/core/pvf/worker/.cargo/musl-gcc

Lines changed: 0 additions & 13 deletions
This file was deleted.

node/core/pvf/worker/bin/execute_worker.rs

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,5 @@
1616

1717
//! Execute worker.
1818
// TODO: Build with musl.
19-
// TODO: Embed into polkadot binary.
2019

21-
polkadot_node_core_pvf_worker::decl_worker_main!(execute);
20+
polkadot_node_core_pvf_worker::decl_worker_main!("execute-worker");

node/core/pvf/worker/bin/prepare_worker.rs

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,5 @@
1616

1717
//! Prepare worker.
1818
// TODO: Build with musl.
19-
// TODO: Embed into polkadot binary.
2019

21-
polkadot_node_core_pvf_worker::decl_worker_main!(prepare);
20+
polkadot_node_core_pvf_worker::decl_worker_main!("prepare-worker");

0 commit comments

Comments
 (0)