diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 73146cac..b9690df8 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -41,7 +41,7 @@ jobs: command: "build" toolchain: "nightly" target: ${{ matrix.platform.target }} - args: "--locked --release --bin=nmo" + args: "--locked --release --bin=nmo --bin=nemo-language-server" strip: true - name: Build archive shell: bash @@ -52,11 +52,13 @@ jobs: cp {README.md,LICENSE-APACHE,LICENSE-MIT} "$name" if [ "${{ matrix.platform.runs-on }}" = "windows-latest" ]; then cp "target/${{ matrix.platform.target }}/release/nmo.exe" "$name/" + cp "target/${{ matrix.platform.target }}/release/nemo-language-server.exe" "$name/" asset=$name.zip 7z a "$asset" "$name" echo ASSET=$asset >> $GITHUB_ENV else cp "target/${{ matrix.platform.target }}/release/nmo" "$name/" + cp "target/${{ matrix.platform.target }}/release/nemo-language-server "$name/" asset=$name.tar.gz tar czf "$asset" "$name" echo ASSET=$asset >> $GITHUB_ENV diff --git a/flake.nix b/flake.nix index da5f3dbf..cab8ee1d 100644 --- a/flake.nix +++ b/flake.nix @@ -12,13 +12,12 @@ rec { utils.url = "github:gytis-ivaskevicius/flake-utils-plus"; }; - outputs = - inputs@{ - self, - utils, - rust-overlay, - ... - }: + outputs = inputs @ { + self, + utils, + rust-overlay, + ... + }: utils.lib.mkFlake { inherit self inputs; @@ -26,317 +25,336 @@ rec { rust-overlay.overlays.default ]; - overlays.default = - final: prev: - let - pkgs = self.packages."${final.system}"; - lib = self.channels.nixpkgs."${final.system}"; - in - { - inherit (pkgs) nemo nemo-python nemo-wasm; - - nodePackages = lib.makeExtensible (lib.extends pkgs.nodePackages prev.nodePackages); + overlays.default = final: prev: let + pkgs = self.packages."${final.system}"; + lib = self.channels.nixpkgs."${final.system}"; + in { + inherit (pkgs) nemo nemo-python nemo-wasm; + + nodePackages = lib.makeExtensible (lib.extends pkgs.nodePackages prev.nodePackages); + }; + + outputsBuilder = channels: let + pkgs = channels.nixpkgs; + toolchain = pkgs.rust-bin.fromRustupToolchainFile ./rust-toolchain.toml; + platform = pkgs.makeRustPlatform { + cargo = toolchain; + rustc = toolchain; }; - - outputsBuilder = - channels: - let - pkgs = channels.nixpkgs; - toolchain = pkgs.rust-bin.fromRustupToolchainFile ./rust-toolchain.toml; - platform = pkgs.makeRustPlatform { - cargo = toolchain; - rustc = toolchain; - }; - defaultBuildInputs = - [ - pkgs.openssl - pkgs.openssl.dev - ] - ++ pkgs.lib.optionals pkgs.stdenv.isDarwin [ - pkgs.darwin.apple_sdk.frameworks.Security - pkgs.darwin.apple_sdk.frameworks.SystemConfiguration - ]; - defaultNativeBuildInputs = [ - toolchain - pkgs.pkg-config + defaultBuildInputs = + [ + pkgs.openssl + pkgs.openssl.dev + ] + ++ pkgs.lib.optionals pkgs.stdenv.isDarwin [ + pkgs.darwin.apple_sdk.frameworks.Security + pkgs.darwin.apple_sdk.frameworks.SystemConfiguration ]; - in - rec { - packages = - let - cargoMeta = (builtins.fromTOML (builtins.readFile ./Cargo.toml)).workspace.package; - inherit (cargoMeta) version; - meta = { - inherit description; - inherit (cargoMeta) homepage; - license = [ - pkgs.lib.licenses.asl20 - pkgs.lib.licenses.mit - ]; - }; - - buildWasm = - target: - { - pname, - src, - version, - meta, - ... - }@args: - pkgs.stdenv.mkDerivation rec { - inherit (args) - version - meta - pname - src - ; - - cargoDeps = platform.importCargoLock { lockFile = ./Cargo.lock; }; - - nativeBuildInputs = - defaultNativeBuildInputs - ++ (with platform; [ - cargoSetupHook - pkgs.wasm-pack - pkgs.nodejs - pkgs.wasm-bindgen-cli - ]); - buildInputs = defaultBuildInputs ++ [ pkgs.nodejs ]; - - buildPhase = '' - runHook preBuild - - mkdir -p $out/lib/node_modules/nemo-wasm - mkdir .cache - mkdir target - export CARGO_HOME=$TMPDIR/.cargo - export CARGO_TARGET_DIR=$TMPDIR/target - export XDG_CACHE_HOME=$TMPDIR/.cache - - cd $src - HOME=$TMPDIR wasm-pack build --target ${target} --weak-refs --mode=no-install --out-dir=$out/lib/node_modules/${pname} nemo-wasm - - runHook postBuild - ''; - }; - in - rec { - nemo = platform.buildRustPackage { - pname = "nemo"; - src = ./.; - meta = meta // { - mainProgram = "nmo"; - }; - inherit version; + defaultNativeBuildInputs = [ + toolchain + pkgs.pkg-config + ]; + in rec { + packages = let + cargoMeta = (builtins.fromTOML (builtins.readFile ./Cargo.toml)).workspace.package; + inherit (cargoMeta) version; + meta = { + inherit description; + inherit (cargoMeta) homepage; + license = [ + pkgs.lib.licenses.asl20 + pkgs.lib.licenses.mit + ]; + }; - cargoLock.lockFile = ./Cargo.lock; + buildWasm = target: { + pname, + src, + version, + meta, + ... + } @ args: + pkgs.stdenv.mkDerivation rec { + inherit + (args) + version + meta + pname + src + ; - buildInputs = defaultBuildInputs; - nativeBuildInputs = - defaultNativeBuildInputs - ++ (with platform; [ - cargoBuildHook - cargoCheckHook - ]); - buildAndTestSubdir = "nemo-cli"; - }; + cargoDeps = platform.importCargoLock {lockFile = ./Cargo.lock;}; - nemo-python = pkgs.python3Packages.buildPythonPackage { - pname = "nemo-python"; - src = ./.; - inherit version meta; + nativeBuildInputs = + defaultNativeBuildInputs + ++ (with platform; [ + cargoSetupHook + pkgs.wasm-pack + pkgs.nodejs + pkgs.wasm-bindgen-cli + ]); + buildInputs = defaultBuildInputs ++ [pkgs.nodejs]; - cargoDeps = platform.importCargoLock { lockFile = ./Cargo.lock; }; + buildPhase = '' + runHook preBuild - buildInputs = defaultBuildInputs; - nativeBuildInputs = - defaultNativeBuildInputs - ++ (with platform; [ - cargoSetupHook - maturinBuildHook - ]); - buildAndTestSubdir = "nemo-python"; + mkdir -p $out/lib/node_modules/nemo-wasm + mkdir .cache + mkdir target + export CARGO_HOME=$TMPDIR/.cargo + export CARGO_TARGET_DIR=$TMPDIR/target + export XDG_CACHE_HOME=$TMPDIR/.cache - checkPhase = '' - PYTHONPATH=''${PYTHONPATH:+''${PYTHONPATH}:}out python3 -m unittest discover -s nemo-python/tests -v - ''; - }; + cd $src + HOME=$TMPDIR wasm-pack build --target ${target} --weak-refs --mode=no-install --out-dir=$out/lib/node_modules/${pname} nemo-wasm - nemo-wasm-node = buildWasm "nodejs" { - pname = "nemo-wasm"; - src = ./.; - inherit version meta; - }; - nemo-wasm-bundler = buildWasm "bundler" { - pname = "nemo-wasm"; - src = ./.; - inherit version meta; + runHook postBuild + ''; + }; + in rec { + nemo = platform.buildRustPackage { + pname = "nemo"; + src = ./.; + meta = + meta + // { + mainProgram = "nmo"; }; - nemo-wasm = nemo-wasm-bundler; + inherit version; - python3 = pkgs.python3.withPackages (ps: [ nemo-python ]); - python = python3; + cargoLock.lockFile = ./Cargo.lock; - nodejs = pkgs.writeShellScriptBin "node" '' - NODE_PATH=${nemo-wasm-node}/lib/node_modules''${NODE_PATH:+":$NODE_PATH"} ${pkgs.nodejs}/bin/node $@ - ''; + buildInputs = defaultBuildInputs; + nativeBuildInputs = + defaultNativeBuildInputs + ++ (with platform; [ + cargoBuildHook + cargoCheckHook + ]); + buildAndTestSubdir = "nemo-cli"; + }; - default = nemo; - }; + nemo-language-server = platform.buildRustPackage { + pname = "nemo-language-server"; + src = ./.; + meta = + meta + // { + mainProgram = "nemo-language-server"; + }; + inherit version; - apps.ci-checks = utils.lib.mkApp { - drv = pkgs.writeShellApplication { - name = "nemo-run-ci-checks"; + cargoLock.lockFile = ./Cargo.lock; - runtimeInputs = pkgs.lib.concatLists [ - defaultBuildInputs - defaultNativeBuildInputs - [ - pkgs.python3 - pkgs.python3Packages.pycodestyle - pkgs.maturin - pkgs.wasm-pack - pkgs.wasm-bindgen-cli - ] - ]; - - text = '' - export RUSTFLAGS"=-Dwarnings" - export RUSTDOCFLAGS="-Dwarnings" - - if [[ ! -f "flake.nix" || ! -f "Cargo.toml" || ! -f "rust-toolchain.toml" ]]; then - echo "This should be run from the top-level of the nemo source tree." - exit 1 - fi - - cargo test - cargo clippy --all-targets - cargo fmt --all -- --check - cargo doc --workspace - - pushd nemo-python - pycodestyle . - VENV="$(mktemp -d)" - python3 -m venv "''${VENV}" - # shellcheck disable=SC1091 - . "''${VENV}"/bin/activate - maturin develop - python3 -m unittest discover tests -v - deactivate - rm -rf "''${VENV}" - popd - - HOME=$TMPDIR wasm-pack build --weak-refs --mode=no-install nemo-wasm - - cargo miri test - ''; - }; + buildInputs = defaultBuildInputs; + nativeBuildInputs = + defaultNativeBuildInputs + ++ (with platform; [ + cargoBuildHook + cargoCheckHook + ]); + buildAndTestSubdir = "nemo-language-server"; }; - checks = - let - runCargo' = - name: env: buildCommand: - pkgs.stdenv.mkDerivation ( - { - preferLocalBuild = true; - allowSubstitutes = false; - - RUSTFLAGS = "-Dwarnings"; - RUSTDOCFLAGS = "-Dwarnings"; - - src = ./.; - cargoDeps = platform.importCargoLock { lockFile = ./Cargo.lock; }; - - buildInputs = defaultBuildInputs; - nativeBuildInputs = - defaultNativeBuildInputs - ++ (with platform; [ - cargoSetupHook - pkgs.python3 - ]); - - inherit name; - - buildPhase = '' - runHook preBuild - mkdir $out - ${buildCommand} - runHook postBuild - ''; - } - // env - ); - runCargo = name: runCargo' name { }; - in - rec { - inherit (packages) - nemo - nemo-python - nemo-wasm - nemo-wasm-node - ; - devShell = devShells.default; + nemo-python = pkgs.python3Packages.buildPythonPackage { + pname = "nemo-python"; + src = ./.; + inherit version meta; - clippy = runCargo "nemo-check-clippy" '' - cargo clippy --all-targets - ''; + cargoDeps = platform.importCargoLock {lockFile = ./Cargo.lock;}; - doc = runCargo "nemo-check-docs" '' - cargo doc --workspace - ''; + buildInputs = defaultBuildInputs; + nativeBuildInputs = + defaultNativeBuildInputs + ++ (with platform; [ + cargoSetupHook + maturinBuildHook + ]); + buildAndTestSubdir = "nemo-python"; + + checkPhase = '' + PYTHONPATH=''${PYTHONPATH:+''${PYTHONPATH}:}out python3 -m unittest discover -s nemo-python/tests -v + ''; + }; - fmt = runCargo "nemo-check-formatting" '' - cargo fmt --all -- --check - ''; + nemo-wasm-node = buildWasm "nodejs" { + pname = "nemo-wasm"; + src = ./.; + inherit version meta; + }; + nemo-wasm-bundler = buildWasm "bundler" { + pname = "nemo-wasm"; + src = ./.; + inherit version meta; + }; + nemo-wasm-web = buildWasm "web" { + pname = "nemo-wasm"; + src = ./.; + inherit version meta; + }; + nemo-wasm = nemo-wasm-bundler; - test = runCargo "nemo-check-tests" '' - cargo test - ''; + python3 = pkgs.python3.withPackages (ps: [nemo-python]); + python = python3; - python-codestyle = - pkgs.runCommandLocal "nemo-check-python-codestyle" - { - nativeBuildInputs = [ pkgs.python3Packages.pycodestyle ]; - } - '' - mkdir $out - pycodestyle ${./nemo-python} - ''; - }; + nodejs = pkgs.writeShellScriptBin "node" '' + NODE_PATH=${nemo-wasm-node}/lib/node_modules''${NODE_PATH:+":$NODE_PATH"} ${pkgs.nodejs}/bin/node $@ + ''; - devShells.default = pkgs.mkShell { - NMO_LOG = "debug"; - RUST_LOG = "debug"; - RUST_BACKTRACE = 1; - RUST_SRC_PATH = "${toolchain}/lib/rustlib/src/rust/library"; + default = nemo; + }; - shellHook = '' - export PATH=''${HOME}/.cargo/bin''${PATH+:''${PATH}} - ''; + apps.ci-checks = utils.lib.mkApp { + drv = pkgs.writeShellApplication { + name = "nemo-run-ci-checks"; - buildInputs = pkgs.lib.concatLists [ + runtimeInputs = pkgs.lib.concatLists [ defaultBuildInputs defaultNativeBuildInputs [ - pkgs.cargo-audit - pkgs.cargo-license - pkgs.cargo-tarpaulin - pkgs.gnuplot - pkgs.maturin pkgs.python3 + pkgs.python3Packages.pycodestyle + pkgs.maturin pkgs.wasm-pack pkgs.wasm-bindgen-cli - pkgs.nodejs ] ]; + + text = '' + export RUSTFLAGS"=-Dwarnings" + export RUSTDOCFLAGS="-Dwarnings" + + if [[ ! -f "flake.nix" || ! -f "Cargo.toml" || ! -f "rust-toolchain.toml" ]]; then + echo "This should be run from the top-level of the nemo source tree." + exit 1 + fi + + cargo test + cargo clippy --all-targets + cargo fmt --all -- --check + cargo doc --workspace + + pushd nemo-python + pycodestyle . + VENV="$(mktemp -d)" + python3 -m venv "''${VENV}" + # shellcheck disable=SC1091 + . "''${VENV}"/bin/activate + maturin develop + python3 -m unittest discover tests -v + deactivate + rm -rf "''${VENV}" + popd + + HOME=$TMPDIR wasm-pack build --weak-refs --mode=no-install nemo-wasm + + cargo miri test + ''; }; + }; + + checks = let + runCargo' = name: env: buildCommand: + pkgs.stdenv.mkDerivation ( + { + preferLocalBuild = true; + allowSubstitutes = false; - formatter = channels.nixpkgs.alejandra; + RUSTFLAGS = "-Dwarnings"; + RUSTDOCFLAGS = "-Dwarnings"; + + src = ./.; + cargoDeps = platform.importCargoLock {lockFile = ./Cargo.lock;}; + + buildInputs = defaultBuildInputs; + nativeBuildInputs = + defaultNativeBuildInputs + ++ (with platform; [ + cargoSetupHook + pkgs.python3 + ]); + + inherit name; + + buildPhase = '' + runHook preBuild + mkdir $out + ${buildCommand} + runHook postBuild + ''; + } + // env + ); + runCargo = name: runCargo' name {}; + in rec { + inherit + (packages) + nemo + nemo-python + nemo-wasm + nemo-wasm-node + ; + devShell = devShells.default; + + clippy = runCargo "nemo-check-clippy" '' + cargo clippy --all-targets + ''; + + doc = runCargo "nemo-check-docs" '' + cargo doc --workspace + ''; + + fmt = runCargo "nemo-check-formatting" '' + cargo fmt --all -- --check + ''; + + test = runCargo "nemo-check-tests" '' + cargo test + ''; + + python-codestyle = + pkgs.runCommandLocal "nemo-check-python-codestyle" + { + nativeBuildInputs = [pkgs.python3Packages.pycodestyle]; + } + '' + mkdir $out + pycodestyle ${./nemo-python} + ''; }; + + devShells.default = pkgs.mkShell { + NMO_LOG = "debug"; + RUST_LOG = "debug"; + RUST_BACKTRACE = 1; + RUST_SRC_PATH = "${toolchain}/lib/rustlib/src/rust/library"; + + shellHook = '' + export PATH=''${HOME}/.cargo/bin''${PATH+:''${PATH}} + ''; + + buildInputs = pkgs.lib.concatLists [ + defaultBuildInputs + defaultNativeBuildInputs + [ + pkgs.cargo-audit + pkgs.cargo-license + pkgs.cargo-tarpaulin + pkgs.gnuplot + pkgs.maturin + pkgs.python3 + pkgs.wasm-pack + pkgs.wasm-bindgen-cli + pkgs.nodejs + ] + ]; + }; + + formatter = channels.nixpkgs.alejandra; + }; }; } # Local Variables: # apheleia-formatter: alejandra # End: + diff --git a/nemo-physical/src/meta/timing.rs b/nemo-physical/src/meta/timing.rs index 574cf47f..a1e685e6 100644 --- a/nemo-physical/src/meta/timing.rs +++ b/nemo-physical/src/meta/timing.rs @@ -7,12 +7,17 @@ use cpu_time::ProcessTime; use cpu_time::ThreadTime; use linked_hash_map::LinkedHashMap; use once_cell::sync::Lazy; -use std::time::{Duration, Instant}; +#[cfg(not(target_family = "wasm"))] +use std::time::Instant; use std::{ + cmp::Reverse, fmt, str::FromStr, sync::{Mutex, MutexGuard}, + time::Duration, }; +#[cfg(target_family = "wasm")] +use wasmtimer::std::Instant; /// Global instance of the [TimedCode] static TIMECODE_INSTANCE: Lazy> = Lazy::new(|| { @@ -33,8 +38,6 @@ pub struct TimedCodeInfo { #[allow(dead_code)] #[cfg(not(target_family = "wasm"))] start_thread: Option, - #[cfg(target_family = "wasm")] - start_thread: Option, runs: u64, } @@ -189,10 +192,9 @@ impl TimedCode { /// Start the next measurement #[cfg(all(not(test), target_family = "wasm"))] pub fn start(&mut self) { - debug_assert!(self.info.start_thread.is_none()); + debug_assert!(self.info.start_system.is_none()); self.info.start_system = Some(Instant::now()); - self.info.start_thread = Some(wasmtimer::std::Instant::now()); } /// No-op because time measurement is disabled @@ -242,20 +244,13 @@ impl TimedCode { .info .start_system .expect("start() must be called before calling stop()"); - let start_thread = self - .info - .start_thread - .expect("start() must be called before calling stop()"); let duration_system = Instant::now() - start_system; - let duration_thread = wasmtimer::std::Instant::now() - start_thread; self.info.total_system_time += duration_system; - self.info.total_thread_time += duration_thread; self.info.start_system = None; - self.info.start_thread = None; self.info.runs += 1; - duration_thread + duration_system } fn apply_display_option<'a>( @@ -264,15 +259,23 @@ impl TimedCode { ) -> Vec<(&'a String, &'a TimedCode)> { let mut blocks: Vec<(&'a String, &'a TimedCode)> = code.subblocks.iter().collect(); + fn name<'a>(entry: &(&'a String, &TimedCode)) -> &'a String { + entry.0 + } + + #[cfg(not(target_family = "wasm"))] + fn longest_time(entry: &(&String, &TimedCode)) -> Reverse { + Reverse(entry.1.info.total_thread_time) + } + #[cfg(target_family = "wasm")] + fn longest_time(entry: &(&String, &TimedCode)) -> Reverse { + Reverse(entry.1.info.total_system_time) + } + match option.sorting { TimedSorting::Default => {} - TimedSorting::Alphabetical => blocks.sort_by(|a, b| a.0.partial_cmp(b.0).unwrap()), - TimedSorting::LongestThreadTime => blocks.sort_by(|a, b| { - b.1.info - .total_thread_time - .partial_cmp(&a.1.info.total_thread_time) - .unwrap() - }), + TimedSorting::Alphabetical => blocks.sort_by_key(name), + TimedSorting::LongestThreadTime => blocks.sort_by_key(longest_time), }; if option.num_elements > 0 {