add flake, copytoram boot image, wip pxe

This commit is contained in:
illustris 2026-01-10 13:05:09 +05:30
parent 4fb1bd90db
commit aa168397b3
Signed by: illustris
GPG Key ID: 56C8FC0B899FEFA3
9 changed files with 572 additions and 0 deletions

2
.gitignore vendored
View File

@ -1 +1,3 @@
*~
result
*.qcow2

141
README.md
View File

@ -104,11 +104,152 @@ python3 --version
---
## Nix-Based Setup (Alternative)
This workshop includes a Nix flake for reproducible environments. Use this if you have Nix installed or want a pre-configured bootable image.
### Quick Reference
| Goal | Command |
|------|---------|
| Dev shell with all tools | `nix develop` |
| Apply tools to Ubuntu | `nix run github:numtide/system-manager -- switch --flake .` |
| Build bootable USB ISO | `nix build .#iso` |
| Build netboot files | `nix build .#netboot` |
### Development Shell
Get all workshop tools in your current shell without installing anything system-wide:
```bash
cd perf-workshop
nix develop
# Now you have: perf, strace, py-spy, bpftrace, hyperfine, valgrind, flamegraph, pyroscope
perf --version
py-spy --help
```
### System-Manager (Ubuntu/Debian)
Install all workshop tools on an existing Ubuntu system using Nix:
```bash
# Apply the configuration (installs tools via Nix)
nix run 'github:numtide/system-manager' -- switch --flake .
# Configure perf permissions (system-manager can't do this)
sudo /etc/perf-workshop-setup.sh
```
This installs tools into `/nix/store` and adds them to your PATH without conflicting with apt packages.
### Bootable USB Image
Build a complete NixOS image with XFCE desktop, all tools pre-installed, and workshop materials:
```bash
# Build the ISO (~4-5 GB)
nix build .#iso
# Flash to USB (replace sdX with your device)
sudo dd if=result/iso/*.iso of=/dev/sdX bs=4M status=progress conv=fsync
```
**ISO Features:**
- XFCE desktop with auto-login (user: `workshop`, password: `workshop`)
- `copytoram` enabled — boots from USB, runs entirely from RAM (USB can be removed after boot)
- `kernel.perf_event_paranoid=1` pre-configured
- Workshop materials in `/home/workshop/perf-workshop`
- Desktop shortcut to open terminal in workshop directory
- SSH enabled for remote access
**Requirements:** 8+ GB RAM recommended (the system runs from RAM)
### Netboot over LAN
For workshops with many participants, netboot is more efficient than flashing multiple USBs.
```bash
# Build netboot bundle
nix build .#netboot
cd result
# Contents:
# - bzImage (kernel)
# - initrd (initrd with full system, ~2-4 GB)
# - netboot.ipxe (iPXE boot script)
```
**Option 1: Pixiecore (easiest)**
Pixiecore is an all-in-one PXE server — just point it at the files:
```bash
nix shell nixpkgs#pixiecore
# Serve on your LAN (requires root for DHCP proxy)
sudo pixiecore boot bzImage initrd \
--cmdline "$(grep -oP 'imgargs.*? \K.*' netboot.ipxe)"
```
Participants set their BIOS to network boot and get the workshop environment automatically.
**Option 2: dnsmasq + HTTP server**
For more control or integration with existing infrastructure:
```bash
# Terminal 1: Serve files over HTTP
python3 -m http.server 8080
```
Configure dnsmasq (`/etc/dnsmasq.d/workshop.conf`):
```ini
interface=eth0
dhcp-range=192.168.1.100,192.168.1.200,12h
enable-tftp
tftp-root=/path/to/result
dhcp-boot=netboot.ipxe
```
**Option 3: Existing PXE infrastructure**
Copy files to your TFTP/HTTP server and configure your DHCP server to serve `netboot.ipxe`.
### Flake Outputs Reference
```bash
# List all outputs
nix flake show
# Available outputs:
# - devShells.x86_64-linux.default # Development shell
# - packages.x86_64-linux.iso # Bootable ISO image
# - packages.x86_64-linux.netboot # Netboot bundle (kernel + initrd + ipxe)
# - packages.x86_64-linux.netboot-kernel
# - packages.x86_64-linux.netboot-initrd
# - packages.x86_64-linux.netboot-ipxe
# - nixosConfigurations.workshop-iso # NixOS config for ISO
# - nixosConfigurations.workshop-netboot # NixOS config for netboot
# - systemConfigs.default # system-manager config for Ubuntu
```
---
## Directory Structure
```
perf-workshop/
├── README.md # This file
├── flake.nix # Nix flake (dev shell, ISO, netboot)
├── flake.lock # Locked dependencies
├── nix/
│ ├── packages.nix # Shared package list
│ ├── common.nix # Common NixOS configuration
│ ├── iso.nix # ISO-specific configuration
│ ├── netboot.nix # Netboot-specific configuration
│ └── system-manager.nix # Ubuntu system-manager module
├── common/
│ └── CHEATSHEET.md # Quick reference card
├── scenario1-python-to-c/

82
flake.lock generated Normal file
View File

@ -0,0 +1,82 @@
{
"nodes": {
"flake-utils": {
"inputs": {
"systems": "systems"
},
"locked": {
"lastModified": 1731533236,
"narHash": "sha256-l0KFg5HjrsfsO/JpG+r7fRrqm12kzFHyUHqHCVpMMbI=",
"owner": "numtide",
"repo": "flake-utils",
"rev": "11707dc2f618dd54ca8739b309ec4fc024de578b",
"type": "github"
},
"original": {
"owner": "numtide",
"repo": "flake-utils",
"type": "github"
}
},
"nixpkgs": {
"locked": {
"lastModified": 1767767207,
"narHash": "sha256-Mj3d3PfwltLmukFal5i3fFt27L6NiKXdBezC1EBuZs4=",
"owner": "nixos",
"repo": "nixpkgs",
"rev": "5912c1772a44e31bf1c63c0390b90501e5026886",
"type": "github"
},
"original": {
"owner": "nixos",
"ref": "nixos-unstable",
"repo": "nixpkgs",
"type": "github"
}
},
"root": {
"inputs": {
"flake-utils": "flake-utils",
"nixpkgs": "nixpkgs",
"system-manager": "system-manager"
}
},
"system-manager": {
"inputs": {
"nixpkgs": [
"nixpkgs"
]
},
"locked": {
"lastModified": 1767765652,
"narHash": "sha256-brTUOSGRmUCU0xJZI/aD5jUYZJm4RhqMRfkzS4veohg=",
"owner": "numtide",
"repo": "system-manager",
"rev": "85610060c48a0b9f1883d5b2525866fc6ddbbe03",
"type": "github"
},
"original": {
"owner": "numtide",
"repo": "system-manager",
"type": "github"
}
},
"systems": {
"locked": {
"lastModified": 1681028828,
"narHash": "sha256-Vy1rq5AaRuLzOxct8nz4T6wlgyUR7zLU309k9mBC768=",
"owner": "nix-systems",
"repo": "default",
"rev": "da67096a3b9bf56a91d16901293e51ba5b49a27e",
"type": "github"
},
"original": {
"owner": "nix-systems",
"repo": "default",
"type": "github"
}
}
},
"root": "root",
"version": 7
}

144
flake.nix Normal file
View File

@ -0,0 +1,144 @@
{
description = "Linux Performance Engineering Workshop";
inputs = {
nixpkgs.url = "github:nixos/nixpkgs/nixos-unstable";
system-manager = {
url = "github:numtide/system-manager";
inputs.nixpkgs.follows = "nixpkgs";
};
flake-utils.url = "github:numtide/flake-utils";
};
outputs = { self, nixpkgs, system-manager, flake-utils }:
let
# Workshop source for embedding in ISO
workshopSrc = builtins.path {
path = ./.;
name = "perf-workshop";
filter = path: type:
let
baseName = baseNameOf path;
in
# Exclude nix build artifacts and git
!(baseName == "result" ||
baseName == ".git" ||
baseName == "flake.lock" ||
nixpkgs.lib.hasSuffix "~" baseName);
};
in
flake-utils.lib.eachSystem [ "x86_64-linux" "aarch64-linux" ] (system:
let
pkgs = nixpkgs.legacyPackages.${system};
workshopPackages = import ./nix/packages.nix { inherit pkgs; };
in
{
# Development shell with all workshop tools
devShells.default = pkgs.mkShell {
packages = workshopPackages;
shellHook = ''
echo "Linux Performance Workshop Development Environment"
echo ""
echo "Available tools: perf, strace, py-spy, hyperfine, bpftrace, ..."
echo "Run 'make' in any scenario directory to build examples"
'';
};
# Package containing workshop materials
packages.workshop-materials = pkgs.runCommand "workshop-materials" {} ''
mkdir -p $out/share/perf-workshop
cp -r ${workshopSrc}/* $out/share/perf-workshop/
'';
}
) // {
# System-manager configuration for Ubuntu
systemConfigs.default = system-manager.lib.makeSystemConfig {
modules = [
./nix/system-manager.nix
];
};
# NixOS configuration for bootable workshop ISO
nixosConfigurations.workshop-iso = nixpkgs.lib.nixosSystem {
system = "x86_64-linux";
specialArgs = { inherit workshopSrc; };
modules = [
"${nixpkgs}/nixos/modules/installer/cd-dvd/installation-cd-graphical-base.nix"
./nix/iso.nix
];
};
# NixOS configuration for netboot
nixosConfigurations.workshop-netboot = nixpkgs.lib.nixosSystem {
system = "x86_64-linux";
specialArgs = { inherit workshopSrc; };
modules = [
"${nixpkgs}/nixos/modules/installer/netboot/netboot.nix"
"${nixpkgs}/nixos/modules/installer/cd-dvd/installation-cd-graphical-base.nix"
./nix/netboot.nix
];
};
# Convenient alias for building the ISO
packages.x86_64-linux.iso =
self.nixosConfigurations.workshop-iso.config.system.build.isoImage;
# Netboot artifacts
packages.x86_64-linux.netboot-kernel =
self.nixosConfigurations.workshop-netboot.config.system.build.kernel;
packages.x86_64-linux.netboot-initrd =
self.nixosConfigurations.workshop-netboot.config.system.build.netbootRamdisk;
packages.x86_64-linux.netboot-ipxe =
self.nixosConfigurations.workshop-netboot.config.system.build.netbootIpxeScript;
# Bundle netboot files for easy serving
packages.x86_64-linux.netboot = let
pkgs = nixpkgs.legacyPackages.x86_64-linux;
cfg = self.nixosConfigurations.workshop-netboot.config;
kernel = "${cfg.system.build.kernel}/bzImage";
initrd = "${cfg.system.build.netbootRamdisk}/initrd";
in pkgs.runCommand "workshop-netboot" {} ''
mkdir -p $out
ln -s ${kernel} $out/bzImage
ln -s ${initrd} $out/initrd
cp ${cfg.system.build.netbootIpxeScript} $out/netboot.ipxe
cat > $out/README.md << 'EOF'
# Workshop Netboot Files
## Quick Start with Pixiecore (easiest)
```bash
# Serve on your LAN (requires root for DHCP)
sudo pixiecore boot bzImage initrd --cmdline "$(grep -oP 'imgargs.*? \K.*' netboot.ipxe)"
```
## Using dnsmasq + HTTP server
1. Start HTTP server in this directory:
```bash
python3 -m http.server 8080
```
2. Configure dnsmasq (adjust interface/IP):
```
interface=eth0
dhcp-range=192.168.1.100,192.168.1.200,12h
enable-tftp
tftp-root=/path/to/this/dir
dhcp-boot=netboot.ipxe
```
3. For UEFI clients, you may need iPXE chainloading.
## Files
- bzImage: Linux kernel
- initrd: Initial ramdisk (contains full system)
- netboot.ipxe: iPXE boot script
EOF
'';
};
}

100
nix/common.nix Normal file
View File

@ -0,0 +1,100 @@
# Common NixOS configuration shared between ISO and netboot
{ config, lib, pkgs, workshopSrc, ... }:
let
workshopPackages = import ./packages.nix {
inherit pkgs;
kernelPackages = config.boot.kernelPackages;
};
in
{
# System identification
system.stateVersion = "24.11";
# Use a recent stable kernel
boot.kernelPackages = pkgs.linuxPackages_6_12;
# Set perf permissions for non-root users
boot.kernel.sysctl = {
"kernel.perf_event_paranoid" = 1;
"kernel.kptr_restrict" = 0; # Allow reading kernel symbols
};
# Workshop packages
environment.systemPackages = workshopPackages ++ (with pkgs; [
# Additional GUI utilities
firefox # for viewing flamegraphs
xfce4-terminal
]);
# Create workshop user with auto-login
users.users.workshop = {
isNormalUser = true;
description = "Workshop User";
extraGroups = [ "wheel" "video" "audio" "networkmanager" ];
initialPassword = "workshop";
home = "/home/workshop";
};
# Auto-login to workshop user
services.displayManager.autoLogin = {
enable = true;
user = "workshop";
};
# Allow passwordless sudo for workshop user
security.sudo.wheelNeedsPassword = false;
# XFCE desktop environment
services.xserver.desktopManager.xfce.enable = true;
services.displayManager.defaultSession = "xfce";
# Embed workshop materials into home directory
system.activationScripts.workshopMaterials = ''
mkdir -p /home/workshop/perf-workshop
cp -rT ${workshopSrc} /home/workshop/perf-workshop
chmod -R u+w /home/workshop/perf-workshop
chown -R workshop:users /home/workshop/perf-workshop
'';
# Desktop shortcut for workshop
environment.etc."skel/Desktop/Workshop.desktop".text = ''
[Desktop Entry]
Type=Application
Name=Performance Workshop
Comment=Open terminal in workshop directory
Exec=xfce4-terminal --working-directory=/home/workshop/perf-workshop
Icon=utilities-terminal
Terminal=false
Categories=Development;
'';
# Copy desktop shortcut for workshop user
system.activationScripts.workshopDesktop = ''
mkdir -p /home/workshop/Desktop
cp /etc/skel/Desktop/Workshop.desktop /home/workshop/Desktop/
chown -R workshop:users /home/workshop/Desktop
chmod +x /home/workshop/Desktop/Workshop.desktop
'';
# Networking
networking = {
hostName = "perf-workshop";
networkmanager.enable = true;
};
# Enable SSH for remote access (useful for debugging)
services.openssh = {
enable = true;
settings = {
PermitRootLogin = "no";
PasswordAuthentication = true;
};
};
# Timezone (can be changed by user)
time.timeZone = "Asia/Kolkata";
# Locale
i18n.defaultLocale = "en_US.UTF-8";
}

17
nix/iso.nix Normal file
View File

@ -0,0 +1,17 @@
# NixOS ISO-specific configuration
{ config, lib, pkgs, workshopSrc, ... }:
{
imports = [ ./common.nix ];
# Enable copytoram - boots from USB, runs entirely from RAM
boot.kernelParams = [ "copytoram" ];
# ISO image customization
isoImage = {
volumeID = lib.mkForce "PERF_WORKSHOP";
makeEfiBootable = true;
makeUsbBootable = true;
};
image.fileName = lib.mkForce "perf-workshop-${config.system.nixos.label}-x86_64.iso";
}

8
nix/netboot.nix Normal file
View File

@ -0,0 +1,8 @@
# NixOS netboot-specific configuration
{ config, lib, pkgs, workshopSrc, ... }:
{
imports = [ ./common.nix ];
# Netboot runs entirely from RAM by default (initrd contains squashfs)
}

45
nix/packages.nix Normal file
View File

@ -0,0 +1,45 @@
# Shared package list for the Linux Performance Workshop
{ pkgs, kernelPackages ? pkgs.linuxPackages }:
with pkgs; [
# Build essentials
gcc
gnumake
binutils
pkg-config
# Performance and tracing tools
perf
strace
ltrace
htop
bpftrace
# Python ecosystem
(python3.withPackages (ps: with ps; [
pip
flask # for scenario7 pyroscope demo
]))
py-spy
# Benchmarking and debugging
hyperfine
valgrind
flamegraph
# USDT/SDT support (provides sys/sdt.h)
libsystemtap
# Continuous profiling
pyroscope
# Utilities
curl
wget
git
file
which
less
vim
nano
]

33
nix/system-manager.nix Normal file
View File

@ -0,0 +1,33 @@
# System-manager module for Ubuntu systems
{ config, lib, pkgs, ... }:
let
workshopPackages = import ./packages.nix { inherit pkgs; };
in
{
config = {
nixpkgs.hostPlatform = "x86_64-linux";
environment.systemPackages = workshopPackages;
# Create a script to configure perf permissions
# (system-manager cannot set sysctl directly)
environment.etc."perf-workshop-setup.sh" = {
mode = "0755";
text = ''
#!/bin/sh
# Run this script to enable perf for non-root users
echo "Setting kernel.perf_event_paranoid=1..."
sudo sysctl -w kernel.perf_event_paranoid=1
# Make it persistent
if ! grep -q "kernel.perf_event_paranoid" /etc/sysctl.conf 2>/dev/null; then
echo "kernel.perf_event_paranoid=1" | sudo tee -a /etc/sysctl.conf
echo "Added to /etc/sysctl.conf for persistence"
fi
echo "Done! You can now use perf as a regular user."
'';
};
};
}