mirror of
https://github.com/Devolutions/IronRDP.git
synced 2025-07-07 17:45:01 +00:00
feat(benches): add perfenc
Make some internal APIs publicly visible thanks to "visibility" when compiling with the "__bench" feature. ("testsuite-core" also learned "__bench", because fast_path.rs is a shared file) Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>
This commit is contained in:
parent
fcb390140d
commit
dd787af5a0
11 changed files with 285 additions and 3 deletions
33
Cargo.lock
generated
33
Cargo.lock
generated
|
@ -416,6 +416,20 @@ version = "1.7.1"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "bb97d56060ee67d285efb8001fec9d2a4c710c32efd2e14b5cbb5ba71930fc2d"
|
checksum = "bb97d56060ee67d285efb8001fec9d2a4c710c32efd2e14b5cbb5ba71930fc2d"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "benches"
|
||||||
|
version = "0.1.0"
|
||||||
|
dependencies = [
|
||||||
|
"anyhow",
|
||||||
|
"async-trait",
|
||||||
|
"bytesize",
|
||||||
|
"ironrdp",
|
||||||
|
"pico-args",
|
||||||
|
"tokio",
|
||||||
|
"tracing",
|
||||||
|
"tracing-subscriber",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "bindgen"
|
name = "bindgen"
|
||||||
version = "0.69.5"
|
version = "0.69.5"
|
||||||
|
@ -582,6 +596,12 @@ version = "1.10.1"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "d71b6127be86fdcfddb610f7182ac57211d4b18a3e9c82eb2d17662f2227ad6a"
|
checksum = "d71b6127be86fdcfddb610f7182ac57211d4b18a3e9c82eb2d17662f2227ad6a"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "bytesize"
|
||||||
|
version = "2.0.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "a3c8f83209414aacf0eeae3cf730b18d6981697fba62f200fcfb92b9f082acba"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "calloop"
|
name = "calloop"
|
||||||
version = "0.13.0"
|
version = "0.13.0"
|
||||||
|
@ -2707,6 +2727,7 @@ dependencies = [
|
||||||
"tokio",
|
"tokio",
|
||||||
"tokio-rustls",
|
"tokio-rustls",
|
||||||
"tracing",
|
"tracing",
|
||||||
|
"visibility",
|
||||||
"x509-cert",
|
"x509-cert",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
@ -2765,6 +2786,7 @@ dependencies = [
|
||||||
"pretty_assertions",
|
"pretty_assertions",
|
||||||
"proptest",
|
"proptest",
|
||||||
"rstest",
|
"rstest",
|
||||||
|
"visibility",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
|
@ -5685,6 +5707,17 @@ version = "0.9.5"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "0b928f33d975fc6ad9f86c8f283853ad26bdd5b10b7f1542aa2fa15e2289105a"
|
checksum = "0b928f33d975fc6ad9f86c8f283853ad26bdd5b10b7f1542aa2fa15e2289105a"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "visibility"
|
||||||
|
version = "0.1.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "d674d135b4a8c1d7e813e2f8d1c9a58308aee4a680323066025e53132218bd91"
|
||||||
|
dependencies = [
|
||||||
|
"proc-macro2",
|
||||||
|
"quote",
|
||||||
|
"syn",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "vswhom"
|
name = "vswhom"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
[workspace]
|
[workspace]
|
||||||
members = [
|
members = [
|
||||||
"crates/*",
|
"crates/*",
|
||||||
|
"benches",
|
||||||
"xtask",
|
"xtask",
|
||||||
"ffi",
|
"ffi",
|
||||||
]
|
]
|
||||||
|
|
31
benches/Cargo.toml
Normal file
31
benches/Cargo.toml
Normal file
|
@ -0,0 +1,31 @@
|
||||||
|
[package]
|
||||||
|
name = "benches"
|
||||||
|
version = "0.1.0"
|
||||||
|
edition.workspace = true
|
||||||
|
license.workspace = true
|
||||||
|
homepage.workspace = true
|
||||||
|
repository.workspace = true
|
||||||
|
authors.workspace = true
|
||||||
|
keywords.workspace = true
|
||||||
|
categories.workspace = true
|
||||||
|
|
||||||
|
[[bin]]
|
||||||
|
name = "perfenc"
|
||||||
|
path = "src/perfenc.rs"
|
||||||
|
|
||||||
|
[dependencies]
|
||||||
|
anyhow = "1.0.98"
|
||||||
|
async-trait = "0.1.88"
|
||||||
|
bytesize = "2.0.1"
|
||||||
|
ironrdp = { path = "../crates/ironrdp", features = [
|
||||||
|
"server",
|
||||||
|
"pdu",
|
||||||
|
"__bench",
|
||||||
|
] }
|
||||||
|
pico-args = "0.5.0"
|
||||||
|
tokio = { version = "1", features = ["sync", "fs"] }
|
||||||
|
tracing-subscriber = { version = "0.3", features = ["env-filter"] }
|
||||||
|
tracing = { version = "0.1", features = ["log"] }
|
||||||
|
|
||||||
|
[lints]
|
||||||
|
workspace = true
|
193
benches/src/perfenc.rs
Normal file
193
benches/src/perfenc.rs
Normal file
|
@ -0,0 +1,193 @@
|
||||||
|
#![allow(unused_crate_dependencies)] // False positives because there are both a library and a binary.
|
||||||
|
#![allow(clippy::print_stderr)]
|
||||||
|
#![allow(clippy::print_stdout)]
|
||||||
|
|
||||||
|
use core::time::Duration;
|
||||||
|
use std::{io::Write, time::Instant};
|
||||||
|
|
||||||
|
use anyhow::Context;
|
||||||
|
use ironrdp::pdu::rdp::capability_sets::{CmdFlags, EntropyBits};
|
||||||
|
use ironrdp::server::{
|
||||||
|
bench::encoder::{UpdateEncoder, UpdateEncoderCodecs},
|
||||||
|
BitmapUpdate, DesktopSize, DisplayUpdate, PixelFormat, RdpServerDisplayUpdates,
|
||||||
|
};
|
||||||
|
use tokio::{fs::File, io::AsyncReadExt, time::sleep};
|
||||||
|
|
||||||
|
#[tokio::main(flavor = "current_thread")]
|
||||||
|
async fn main() -> Result<(), anyhow::Error> {
|
||||||
|
setup_logging()?;
|
||||||
|
let mut args = pico_args::Arguments::from_env();
|
||||||
|
|
||||||
|
if args.contains(["-h", "--help"]) {
|
||||||
|
println!("Usage: perfenc [OPTIONS] <RGBX_INPUT_FILENAME>");
|
||||||
|
println!();
|
||||||
|
println!("Measure the performance of the IronRDP server encoder, given a raw RGBX video input file.");
|
||||||
|
println!();
|
||||||
|
println!("Options:");
|
||||||
|
println!(" --width <WIDTH> Width of the display (default: 3840)");
|
||||||
|
println!(" --height <HEIGHT> Height of the display (default: 2400)");
|
||||||
|
println!(" --codec <CODEC> Codec to use (default: remotefx)");
|
||||||
|
println!(" Valid values: remotefx, bitmap, none");
|
||||||
|
println!(" --fps <FPS> Frames per second (default: none)");
|
||||||
|
std::process::exit(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
let width = args.opt_value_from_str("--width")?.unwrap_or(3840);
|
||||||
|
let height = args.opt_value_from_str("--height")?.unwrap_or(2400);
|
||||||
|
let codec = args.opt_value_from_str("--codec")?.unwrap_or_else(OptCodec::default);
|
||||||
|
let fps = args.opt_value_from_str("--fps")?.unwrap_or(0);
|
||||||
|
|
||||||
|
let filename: String = args.free_from_str().context("missing RGBX input filename")?;
|
||||||
|
let file = File::open(&filename)
|
||||||
|
.await
|
||||||
|
.with_context(|| format!("Failed to open file: {}", filename))?;
|
||||||
|
|
||||||
|
let mut flags = CmdFlags::all();
|
||||||
|
let mut update_codecs = UpdateEncoderCodecs::new();
|
||||||
|
|
||||||
|
match codec {
|
||||||
|
OptCodec::RemoteFX => update_codecs.set_remotefx(Some((EntropyBits::Rlgr3, 0))),
|
||||||
|
OptCodec::Bitmap => {
|
||||||
|
flags -= CmdFlags::SET_SURFACE_BITS;
|
||||||
|
}
|
||||||
|
OptCodec::None => {}
|
||||||
|
};
|
||||||
|
|
||||||
|
let mut encoder = UpdateEncoder::new(DesktopSize { width, height }, flags, update_codecs);
|
||||||
|
|
||||||
|
let mut total_raw = 0u64;
|
||||||
|
let mut total_enc = 0u64;
|
||||||
|
let mut n_updates = 0u64;
|
||||||
|
let mut updates = DisplayUpdates::new(file, DesktopSize { width, height }, fps);
|
||||||
|
while let Some(up) = updates.next_update().await {
|
||||||
|
if let DisplayUpdate::Bitmap(ref up) = up {
|
||||||
|
total_raw += up.data.len() as u64;
|
||||||
|
} else {
|
||||||
|
eprintln!("Invalid update");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
let mut iter = encoder.update(up);
|
||||||
|
loop {
|
||||||
|
let Some(frag) = iter.next().await else {
|
||||||
|
break;
|
||||||
|
};
|
||||||
|
let len = frag?.data.len() as u64;
|
||||||
|
total_enc += len;
|
||||||
|
}
|
||||||
|
n_updates += 1;
|
||||||
|
print!(".");
|
||||||
|
std::io::stdout().flush().unwrap();
|
||||||
|
}
|
||||||
|
println!();
|
||||||
|
|
||||||
|
let ratio = total_enc as f64 / total_raw as f64;
|
||||||
|
let percent = 100.0 - ratio * 100.0;
|
||||||
|
println!("Encoder: {:?}", encoder);
|
||||||
|
println!("Nb updates: {:?}", n_updates);
|
||||||
|
println!(
|
||||||
|
"Sum of bytes: {}/{} ({:.2}%)",
|
||||||
|
bytesize::ByteSize(total_enc),
|
||||||
|
bytesize::ByteSize(total_raw),
|
||||||
|
percent,
|
||||||
|
);
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
struct DisplayUpdates {
|
||||||
|
file: File,
|
||||||
|
desktop_size: DesktopSize,
|
||||||
|
fps: u64,
|
||||||
|
last_update_time: Option<Instant>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl DisplayUpdates {
|
||||||
|
fn new(file: File, desktop_size: DesktopSize, fps: u64) -> Self {
|
||||||
|
Self {
|
||||||
|
file,
|
||||||
|
desktop_size,
|
||||||
|
fps,
|
||||||
|
last_update_time: None,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[async_trait::async_trait]
|
||||||
|
impl RdpServerDisplayUpdates for DisplayUpdates {
|
||||||
|
async fn next_update(&mut self) -> Option<DisplayUpdate> {
|
||||||
|
let stride = self.desktop_size.width as usize * 4;
|
||||||
|
let frame_size = stride * self.desktop_size.height as usize;
|
||||||
|
let mut buf = vec![0u8; frame_size];
|
||||||
|
if self.file.read_exact(&mut buf).await.is_err() {
|
||||||
|
return None;
|
||||||
|
}
|
||||||
|
|
||||||
|
let now = Instant::now();
|
||||||
|
if let Some(last_update_time) = self.last_update_time {
|
||||||
|
let elapsed = now - last_update_time;
|
||||||
|
if self.fps > 0 && elapsed < Duration::from_millis(1000 / self.fps) {
|
||||||
|
sleep(Duration::from_millis(
|
||||||
|
1000 / self.fps - u64::try_from(elapsed.as_millis()).unwrap(),
|
||||||
|
))
|
||||||
|
.await;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
self.last_update_time = Some(now);
|
||||||
|
|
||||||
|
let up = DisplayUpdate::Bitmap(BitmapUpdate {
|
||||||
|
x: 0,
|
||||||
|
y: 0,
|
||||||
|
width: self.desktop_size.width.try_into().unwrap(),
|
||||||
|
height: self.desktop_size.height.try_into().unwrap(),
|
||||||
|
format: PixelFormat::RgbX32,
|
||||||
|
data: buf.into(),
|
||||||
|
stride,
|
||||||
|
});
|
||||||
|
Some(up)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn setup_logging() -> anyhow::Result<()> {
|
||||||
|
use tracing::metadata::LevelFilter;
|
||||||
|
use tracing_subscriber::prelude::*;
|
||||||
|
use tracing_subscriber::EnvFilter;
|
||||||
|
|
||||||
|
let fmt_layer = tracing_subscriber::fmt::layer().compact();
|
||||||
|
|
||||||
|
let env_filter = EnvFilter::builder()
|
||||||
|
.with_default_directive(LevelFilter::WARN.into())
|
||||||
|
.with_env_var("IRONRDP_LOG")
|
||||||
|
.from_env_lossy();
|
||||||
|
|
||||||
|
tracing_subscriber::registry()
|
||||||
|
.with(fmt_layer)
|
||||||
|
.with(env_filter)
|
||||||
|
.try_init()
|
||||||
|
.context("failed to set tracing global subscriber")?;
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
enum OptCodec {
|
||||||
|
RemoteFX,
|
||||||
|
Bitmap,
|
||||||
|
None,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Default for OptCodec {
|
||||||
|
fn default() -> Self {
|
||||||
|
Self::RemoteFX
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl core::str::FromStr for OptCodec {
|
||||||
|
type Err = anyhow::Error;
|
||||||
|
|
||||||
|
fn from_str(s: &str) -> Result<Self, Self::Err> {
|
||||||
|
match s {
|
||||||
|
"remotefx" => Ok(Self::RemoteFX),
|
||||||
|
"bitmap" => Ok(Self::Bitmap),
|
||||||
|
"none" => Ok(Self::None),
|
||||||
|
_ => Err(anyhow::anyhow!("unknown codec: {}", s)),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -22,7 +22,7 @@ rayon = ["dep:rayon"]
|
||||||
|
|
||||||
# Internal (PRIVATE!) features used to aid testing.
|
# Internal (PRIVATE!) features used to aid testing.
|
||||||
# Don't rely on these whatsoever. They may disappear at any time.
|
# Don't rely on these whatsoever. They may disappear at any time.
|
||||||
__bench = []
|
__bench = ["dep:visibility"]
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
anyhow = "1.0"
|
anyhow = "1.0"
|
||||||
|
@ -46,6 +46,7 @@ x509-cert = { version = "0.2.5", optional = true }
|
||||||
rustls-pemfile = { version = "2.2.0", optional = true }
|
rustls-pemfile = { version = "2.2.0", optional = true }
|
||||||
rayon = { version = "1.10.0", optional = true }
|
rayon = { version = "1.10.0", optional = true }
|
||||||
bytes = "1"
|
bytes = "1"
|
||||||
|
visibility = { version = "0.1", optional = true }
|
||||||
|
|
||||||
[dev-dependencies]
|
[dev-dependencies]
|
||||||
tokio = { version = "1", features = ["sync"] }
|
tokio = { version = "1", features = ["sync"] }
|
||||||
|
|
|
@ -8,10 +8,13 @@ const MAX_FASTPATH_UPDATE_SIZE: usize = 16_374;
|
||||||
|
|
||||||
const FASTPATH_HEADER_SIZE: usize = 6;
|
const FASTPATH_HEADER_SIZE: usize = 6;
|
||||||
|
|
||||||
|
#[allow(unreachable_pub)]
|
||||||
|
#[cfg_attr(feature = "__bench", visibility::make(pub))]
|
||||||
pub(crate) struct UpdateFragmenter {
|
pub(crate) struct UpdateFragmenter {
|
||||||
code: UpdateCode,
|
code: UpdateCode,
|
||||||
index: usize,
|
index: usize,
|
||||||
data: Vec<u8>,
|
#[doc(hidden)] // not part of the public API, used by benchmarks
|
||||||
|
pub data: Vec<u8>,
|
||||||
position: usize,
|
position: usize,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -29,16 +29,19 @@ enum CodecId {
|
||||||
None = 0x0,
|
None = 0x0,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg_attr(feature = "__bench", visibility::make(pub))]
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub(crate) struct UpdateEncoderCodecs {
|
pub(crate) struct UpdateEncoderCodecs {
|
||||||
remotefx: Option<(EntropyBits, u8)>,
|
remotefx: Option<(EntropyBits, u8)>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl UpdateEncoderCodecs {
|
impl UpdateEncoderCodecs {
|
||||||
|
#[cfg_attr(feature = "__bench", visibility::make(pub))]
|
||||||
pub(crate) fn new() -> Self {
|
pub(crate) fn new() -> Self {
|
||||||
Self { remotefx: None }
|
Self { remotefx: None }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg_attr(feature = "__bench", visibility::make(pub))]
|
||||||
pub(crate) fn set_remotefx(&mut self, remotefx: Option<(EntropyBits, u8)>) {
|
pub(crate) fn set_remotefx(&mut self, remotefx: Option<(EntropyBits, u8)>) {
|
||||||
self.remotefx = remotefx
|
self.remotefx = remotefx
|
||||||
}
|
}
|
||||||
|
@ -50,6 +53,7 @@ impl Default for UpdateEncoderCodecs {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg_attr(feature = "__bench", visibility::make(pub))]
|
||||||
pub(crate) struct UpdateEncoder {
|
pub(crate) struct UpdateEncoder {
|
||||||
desktop_size: DesktopSize,
|
desktop_size: DesktopSize,
|
||||||
framebuffer: Option<Framebuffer>,
|
framebuffer: Option<Framebuffer>,
|
||||||
|
@ -65,6 +69,7 @@ impl fmt::Debug for UpdateEncoder {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl UpdateEncoder {
|
impl UpdateEncoder {
|
||||||
|
#[cfg_attr(feature = "__bench", visibility::make(pub))]
|
||||||
pub(crate) fn new(desktop_size: DesktopSize, surface_flags: CmdFlags, codecs: UpdateEncoderCodecs) -> Self {
|
pub(crate) fn new(desktop_size: DesktopSize, surface_flags: CmdFlags, codecs: UpdateEncoderCodecs) -> Self {
|
||||||
let bitmap_updater = if surface_flags.contains(CmdFlags::SET_SURFACE_BITS) {
|
let bitmap_updater = if surface_flags.contains(CmdFlags::SET_SURFACE_BITS) {
|
||||||
let mut bitmap = BitmapUpdater::None(NoneHandler);
|
let mut bitmap = BitmapUpdater::None(NoneHandler);
|
||||||
|
@ -85,6 +90,7 @@ impl UpdateEncoder {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg_attr(feature = "__bench", visibility::make(pub))]
|
||||||
pub(crate) fn update(&mut self, update: DisplayUpdate) -> EncoderIter<'_> {
|
pub(crate) fn update(&mut self, update: DisplayUpdate) -> EncoderIter<'_> {
|
||||||
EncoderIter {
|
EncoderIter {
|
||||||
encoder: self,
|
encoder: self,
|
||||||
|
@ -218,12 +224,14 @@ enum State {
|
||||||
Ended,
|
Ended,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg_attr(feature = "__bench", visibility::make(pub))]
|
||||||
pub(crate) struct EncoderIter<'a> {
|
pub(crate) struct EncoderIter<'a> {
|
||||||
encoder: &'a mut UpdateEncoder,
|
encoder: &'a mut UpdateEncoder,
|
||||||
state: State,
|
state: State,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl EncoderIter<'_> {
|
impl EncoderIter<'_> {
|
||||||
|
#[cfg_attr(feature = "__bench", visibility::make(pub))]
|
||||||
pub(crate) async fn next(&mut self) -> Option<Result<UpdateFragmenter>> {
|
pub(crate) async fn next(&mut self) -> Option<Result<UpdateFragmenter>> {
|
||||||
loop {
|
loop {
|
||||||
let state = core::mem::take(&mut self.state);
|
let state = core::mem::take(&mut self.state);
|
||||||
|
|
|
@ -35,5 +35,7 @@ pub mod bench {
|
||||||
pub mod rfx {
|
pub mod rfx {
|
||||||
pub use crate::encoder::rfx::bench::{rfx_enc, rfx_enc_tile};
|
pub use crate::encoder::rfx::bench::{rfx_enc, rfx_enc_tile};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub use crate::encoder::{UpdateEncoder, UpdateEncoderCodecs};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -10,6 +10,12 @@ autotests = false
|
||||||
doctest = false
|
doctest = false
|
||||||
test = false
|
test = false
|
||||||
|
|
||||||
|
[features]
|
||||||
|
# Internal (PRIVATE!) features used to aid testing.
|
||||||
|
# Don't rely on these whatsoever. They may disappear at any time.
|
||||||
|
# Added here because it includes/link to some files from other crates
|
||||||
|
__bench = ["dep:visibility"]
|
||||||
|
|
||||||
[[test]]
|
[[test]]
|
||||||
name = "integration_tests_core"
|
name = "integration_tests_core"
|
||||||
path = "tests/main.rs"
|
path = "tests/main.rs"
|
||||||
|
@ -22,6 +28,7 @@ ironrdp-core.path = "../ironrdp-core"
|
||||||
ironrdp-pdu.path = "../ironrdp-pdu"
|
ironrdp-pdu.path = "../ironrdp-pdu"
|
||||||
lazy_static.workspace = true # TODO: remove in favor of https://doc.rust-lang.org/std/sync/struct.OnceLock.html
|
lazy_static.workspace = true # TODO: remove in favor of https://doc.rust-lang.org/std/sync/struct.OnceLock.html
|
||||||
paste = "1"
|
paste = "1"
|
||||||
|
visibility = { version = "0.1", optional = true }
|
||||||
|
|
||||||
[dev-dependencies]
|
[dev-dependencies]
|
||||||
anyhow = "1"
|
anyhow = "1"
|
||||||
|
|
|
@ -31,6 +31,9 @@ dvc = ["dep:ironrdp-dvc"]
|
||||||
rdpdr = ["dep:ironrdp-rdpdr"]
|
rdpdr = ["dep:ironrdp-rdpdr"]
|
||||||
rdpsnd = ["dep:ironrdp-rdpsnd"]
|
rdpsnd = ["dep:ironrdp-rdpsnd"]
|
||||||
displaycontrol = ["dep:ironrdp-displaycontrol"]
|
displaycontrol = ["dep:ironrdp-displaycontrol"]
|
||||||
|
# Internal (PRIVATE!) features used to aid testing.
|
||||||
|
# Don't rely on these whatsoever. They may disappear at any time.
|
||||||
|
__bench = ["ironrdp-server/__bench"]
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
ironrdp-core = { path = "../ironrdp-core", version = "0.1", optional = true } # public
|
ironrdp-core = { path = "../ironrdp-core", version = "0.1", optional = true } # public
|
||||||
|
|
|
@ -20,7 +20,7 @@ pub fn lints(sh: &Shell) -> anyhow::Result<()> {
|
||||||
// TODO: when 1.74 is released use `--keep-going`: https://doc.rust-lang.org/nightly/cargo/reference/unstable.html#keep-going
|
// TODO: when 1.74 is released use `--keep-going`: https://doc.rust-lang.org/nightly/cargo/reference/unstable.html#keep-going
|
||||||
cmd!(
|
cmd!(
|
||||||
sh,
|
sh,
|
||||||
"{CARGO} clippy --workspace --all-targets --features helper --locked -- -D warnings"
|
"{CARGO} clippy --workspace --all-targets --features helper,__bench --locked -- -D warnings"
|
||||||
)
|
)
|
||||||
.run()?;
|
.run()?;
|
||||||
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue