[{"content":"At NixCon 2025, I had the pleasure of meeting the Founder of DeepComputing, Yuning Liang. I was excited as I ordered their new laptop, the DC ROMA II, a few months prior. It has an ESWIN EIC7700X, an SoC with 8 out of order execution RV64GBC cores. This is a huge upgrade compared to the 4 in-order execution cores on the JH7110 that the VisionFive 2 uses. I started looking into getting Nix \u0026amp; NixOS working on it shortly after receiving it. Surely since I am able to port NixOS to things like the FydeTab Duo and get a VisionFive 2 to work, I should be able to get this system working.\nThe first thing I did was install Nix, however there\u0026rsquo;s no prebuilt binaries for Nix that the installer script utilizes. I took a look at the installer script and found a convinient option called --tarball-url-prefix. I spun up a build of Nix for RISC-V using an Arm cross environment. However, I ended up not needing that due to Hydra conviently having done that for me in Build 312888635 of job nix:master:binaryTarballCross.x86_64-linux.riscv64-unknown-linux-gnu. I managed to even point --tarball-url-prefix to nix-2.33.0pre20251111_af0ac14-riscv64-linux.tar.xz. Once I ran the installer, the installation experience was smooth. I restarted the shell and ran nix --version which told me that I have 2.33.0.\nAfter installing Nix, I decided to try building nix-info. I ran nix-shell -p nix-info which seemed to start smoothly, but was quickly interrupted as bootstrap-tools failed to build. This is a big problem, as the bootstrap-tools derivation is a crucial part of the nixpkgs bootstrap process. It takes a pre-built tarball of various tools like coreutils, gcc, patchelf, and a subset of binutils. It provides the necessary commands to bootstrap nixpkgs from a small footprint and in a sandboxed environment. I managed to cross compile a new bootstrap tools tarball on my Ampere desktop, copied that over and hacked around import \u0026lt;nix/fetchurl.nix\u0026gt; so it did url = \u0026quot;file://${./bootstrap-tools.tar.xz}\u0026quot;; instead of fetching from the tarballs server. This allowed me to use the new bootstrap tools. Once that was done, I attempted another build and the bootstrap tools managed to build. However, this was only a temporary victory.\nAfter chatting with other NixOS contributors, it turns there\u0026rsquo;s an issue in nixpkgs regarding PIE. PIE is a method of allowing programs to be relocated. This is useful on systems with limited address spaces and helps prevent libraries from colliding due to occupying the same address. The issue was discovered by using strace -E LD_DEBUG=all on GCC. This revealed the following logs:\nexecve(\u0026#34;/nix/store/kg61gdq4svvph0c4pcsf867r8nkbiqs7-bootstrap-tools/lib/ld-linux-riscv64-lp64d.so.1\u0026#34;, [\u0026#34;/nix/store/kg61gdq4svvph0c4pcsf8\u0026#34;..., \u0026#34;/nix/store/kg61gdq4svvph0c4pcsf8\u0026#34;0 brk(NULL) = 0x7fff84224000 openat(AT_FDCWD, \u0026#34;/nix/store/kg61gdq4svvph0c4pcsf867r8nkbiqs7-bootstrap-tools/bin/gcc\u0026#34;, O_RDONLY|O_CLOEXEC) = 3 read(3, \u0026#34;\\177ELF\\2\\1\\1\\3\\0\\0\\0\\0\\0\\0\\0\\0\\2\\0\\363\\0\\1\\0\\0\\0\\230\\312\\2\\0\\0\\0\\0\\0\u0026#34;..., 832) = 832 getpid() = 6665 writev(2, [{iov_base=\u0026#34; 6665:\\t\u0026#34;, iov_len=12}, {iov_base=\u0026#34;file=\u0026#34;, iov_len=5}, {iov_base=\u0026#34;/nix/store/kg61gdq4svvph0c4pcsf8\u0026#34;..., iov_len=67}, {iov_base=\u0026#34; [\u0026#34;, iov_len=2}, {iovp ) = 111 mmap(0xf000, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_DENYWRITE, 3, 0) = -1 EPERM (Operation not permitted) close(3) = 0 writev(2, [{iov_base=\u0026#34;/nix/store/kg61gdq4svvph0c4pcsf8\u0026#34;..., iov_len=67}, {iov_base=\u0026#34;: \u0026#34;, iov_len=2}, {iov_base=\u0026#34;error while loading shared libra\u0026#34;..., iov_len=36}, {iov_base=\u0026#34;: t ) = 217 exit_group(127) = ? +++ exited with 127 +++ If you look closely, you\u0026rsquo;ll see the mmap call. It\u0026rsquo;s attempting to map address 0xf000 with a 4kb size and have it be read-write. However, you will notice that the syscall is returning -1 and indicating an error code, EPERM. Not being able to mmap the address is causing a big problem since looking at the ELF header using readelf -l, you can see that is used by the program header (PHDR).\nProgram Headers: Type Offset VirtAddr PhysAddr FileSiz MemSiz Flags Align PHDR 0x0000000000000040 0x000000000000f040 0x000000000000f040 0x00000000000002a0 0x00000000000002a0 R 0x8 RISCV_ATTRIBUT 0x0000000000219e92 0x0000000000000000 0x0000000000000000 0x0000000000000057 0x0000000000000000 R 0x1 GNU_STACK 0x0000000000001000 0x0000000000000000 0x0000000000000000 0x0000000000000000 0x0000000000000000 RW 0x10 LOAD 0x0000000000000000 0x000000000000f000 0x000000000000f000 0x0000000000001000 0x0000000000001000 RW 0x1000 LOAD 0x0000000000001000 0x0000000000010000 0x0000000000010000 0x000000000020ded0 0x000000000020ded0 R E 0x1000 INTERP 0x00000000000142d0 0x00000000000232d0 0x00000000000232d0 0x000000000000005c 0x000000000000005c R 0x1 [Requesting program interpreter: /nix/store/kg61gdq4svvph0c4pcsf867r8nkbiqs7-bootstrap-tools/lib/ld-linux-riscv64-lp64d.so.1] NOTE 0x0000000000014330 0x0000000000023330 0x0000000000023330 0x0000000000000020 0x0000000000000020 R 0x4 GNU_EH_FRAME 0x00000000001c41d8 0x00000000001d31d8 0x00000000001d31d8 0x000000000000967c 0x000000000000967c R 0x4 LOAD 0x000000000020ef58 0x000000000021ef58 0x000000000021ef58 0x000000000000af28 0x00000000000103b8 RW 0x1000 TLS 0x000000000020ef58 0x000000000021ef58 0x000000000021ef58 0x0000000000000000 0x0000000000000010 R 0x8 GNU_RELRO 0x000000000020ef58 0x000000000021ef58 0x000000000021ef58 0x00000000000080a8 0x00000000000080a8 R 0x1 DYNAMIC 0x0000000000216dd0 0x0000000000226dd0 0x0000000000226dd0 0x0000000000000230 0x0000000000000230 RW 0x8 Although this is useful information, it does not clearly state why that is a problem. All of these addresses fit within the RISC-V specification for alignment and generally looks safe. However, if you look at the ELF header, it tells a different story.\nELF Header: Magic: 7f 45 4c 46 02 01 01 03 00 00 00 00 00 00 00 00 Class: ELF64 Data: 2\u0026#39;s complement, little endian Version: 1 (current) OS/ABI: UNIX - GNU ABI Version: 0 Type: EXEC (Executable file) Machine: RISC-V Version: 0x1 Entry point address: 0x2ca98 Start of program headers: 64 (bytes into file) Start of section headers: 2203656 (bytes into file) Flags: 0x5, RVC, double-float ABI Size of this header: 64 (bytes) Size of program headers: 56 (bytes) Number of program headers: 12 Size of section headers: 64 (bytes) Number of section headers: 31 Section header string table index: 30 Now the problem is revealed, the PIE flag is not set. What this means is the kernel is doing the following steps:\nChecks ELF magic Iterate through each section Check the address is lower than vm.mmap_min_addr \u0026amp; PIE is set If the PIE flag is set, ignore the vm.mmap_min_addr sysctl If the address is lower, fails If the address is higher, succeeds Executes This is roughly an oversimplified explanation of how a program is loaded. So we know PIE is not set, however there\u0026rsquo;s the other problem. I ran cat /proc/sys/vm/mmap_min_addr and got back 65536. Now that explains what\u0026rsquo;s going on, the address we\u0026rsquo;re trying to have mapped is lower than what the kernel is permitting. I decided to try sysctl -w vm.mmap_min_addr=4096 and ran the build again.\nAfter attempting to build again, everything continued to work. The next thing to do will be fixing PIE on RISC-V in nixpkgs but that\u0026rsquo;ll be a future thing to do. Until then, I\u0026rsquo;ll be making progress on getting NixOS to boot.\n","date":"2025-11-17T11:50:00+08:00","permalink":"https://tristanxr.com/post/dc-roma-ii-nix/","title":"Nix on the DC ROMA II"},{"content":"Since Wednesday, I\u0026rsquo;ve been hard at work with trying to get SELinux (Security Enhanced Linux) to function on NixOS. This is because I am building a Linux distro called ExpidusOS. One of the goals for that is to implement a mobile OS security setup into the OS. With ExpidusOS being based on NixOS, this means the entire OS is declaratively built. However, it is more in-line with an appliance OS. This is to increase security and make it easier for the end user to utilize.\nPackaging SELinux SELinux was luckily already packaged in nixpkgs, but it hadn\u0026rsquo;t been maintained in a long time. That is until I picked it up last year. I had been a the maintainer of it for about a year. But now, I am finally getting involved in making SELinux on NixOS a reality. The only real work has been making sure there\u0026rsquo;s little existing problems reported and reviewing any pull requests. However, I did have to package the SELinux reference policy. The refpolicy is a simple SELinux policy that provides enough for a usable experience. It is in no way a fully secure policy but it is a good enough policy to work off of.\nTo package it, I started out with a typical Nix derivation which fetches from GitHub. However, I did have to add a few things that are unique like makeFlags. This attribute holds all the flags to pass over to GNU Make as refpolicy is built with GNU Makefiles. One of the few differences was adding in make conf as the configurePhase and passing in the various SELinux userspace tools in through makeFlags. From there, I was able to build the policy. Though, it did end up with $out/usr but that was as simple as adding this to the makeFlags:\n\u0026#34;prefix=${placeholder \u0026#34;out\u0026#34;}\u0026#34; With the refpolicy derivation outputting correctly, it was time to figure out how SELinux works and getting it functioning.\nStarting the SELinux NixOS module The first thing I did on the NixOS side was I created a basic module. This module added libselinux and policycoreutils to environment.systemPackages. It also created /etc/selinux/config, the configuration file which configures SELinux on the distro. I also added a kernel patch via boot.kernelPatches which enabled CONFIG_SECURITY_SELINUX and CONFIG_SECURITY_SELINUX_BOOTPARAM. I then added security=selinux to boot.kernelParams. With this, I booted up the NixOS VM and checked sestatus to ensure SELinux was enabled. However, it reported as disabled. I tried various other kernel parameters and versions of the kernel. This led me to trying systemd with SELinux enabled in systemd.package. I booted up the VM and got a warning saying /etc/selinux/refpolicy/policy/policy.33 did not exist. sestatus also reported that SELinux was indeed enabled. This was the first large step towards getting SELinux working. The next step was getting the policy.33 file to exist.\nGetting a policy loaded Making a policy load on NixOS was a bit of an endeavor as there wasn\u0026rsquo;t many tutorials I could find which explained things very aptly. I checked what Gentoo and Arch Linux does and found that Arch Linux\u0026rsquo;s selinux-refpolicy-git\u0026rsquo;s install script from the AUR is what I needed. The solution I came up with was to tack it into the activation script. This would install the policy upon the NixOS generation was activated.\nAt this point, I got stuck and ran into a broken pipe error. I eventually managed to figure out via verbose mode that it was looking for hll in a FHS path and not within the Nix store. I grepped SELinux\u0026rsquo;s source code and stumbled upon libsemanage having a configuration file format. This would be perfect as it allows for specifying the paths to the various tools semodule calls. I added the paths for hll, load_policy, setfiles, and sefcontext_compile. I also had to tack on the arguments that libsemanage uses by default for the last three tools.\nOnce semanage was using its configuration file inside /etc/selinux, I booted up the VM one more time. The boot stalled and the error about /etc/selinux/refpolicy/policy/policy.33 was still present. I checked the path and found /etc/selinux/refpolicy/policy/policy.34 existed. I checked sestatus and it said the system was using policy v33.\nGetting the right policy version SELinux spitting out policy.34 instead of policy.33 stumpted me. Until, I grepped the SELinux source tree more. I found out that SELinux\u0026rsquo;s userspace tools default to the max version. The max version which at this time is 34. The kernel I was using has an SELinux version of 33. This meant that I had to get refpolicy to build for SELinux policy 33 instead of 34. I found that various tools in SELinux support specifying the version. However, refpolicy has a flag for changing the version. This led me to add two new attributes which can be overridden when building refpolicy, policyVersion and moduleVersion. I also added a policyVersion option to the SELinux module in NixOS.\nAfter rebuilding the VM and deleting the qcow2 image as a precaution, I booted up the VM one more time. It did the usual stall on boot when semanage would install the policy. After about 40 seconds, the system initialization continued. However, the error about the missing policy.33 file went away. Other messages complaining about various systemd things also disappeared. I checked /etc/selinux/refpolicy/policy/policy.33 and it existed. sestatus also mentioned the policy is refpolicy. These two indicated that SELinux is indeed working.\nConfiguring SELinux in nixpkgs With SELinux properly loading a policy, I decided to start cleaning up how SELinux is handled on nixpkgs. I started with checking for everything which optionally added SELinux based on an attribute. I also added a new nixpkgs config flag called selinuxSupport. This config flag is able to rebuild everything from coreutils to postgres and emacs. It enables SELinux support everywhere it is possibly supported. This process was pretty straight forward and went very smoothly.\nUpstreaming into nixpkgs All this work for ExpidusOS had been made with the intention of it going back into nixpkgs and NixOS upstream. I made the following pull requests:\nlibselinux: 3.8 -\u0026gt; 3.8.1 #396105 selinux-refpolicy: init 2.20250213 #396155 pkgs/top-level/config.nix: add selinux support #396168 nixos/selinux: init #396177 These four pull requests ended up being all it takes to get basic SELinux support into NixOS and nixpkgs. In my time of looking at various things, I came across an RFC ([RFC 0041] SELinux Support #41). Reading through it, I see why SELinux support hadn\u0026rsquo;t been done to this degree before. However, I believe the work I have done here and the ExpidusOS project to push SELinux support to be capable of securing a NixOS appliance OS.\nNext steps The next step from here is get everything upstreamed. From there, I plan on working out a way to do declarative policy creation within the NixOS module system. This would make handling policies better than using refpolicy. From there, it can be investigated how this impacts the Nix daemon and building in general.\n","date":"2025-04-05T18:00:00+08:00","permalink":"https://tristanxr.com/post/selinux-on-nixos/","title":"SELinux on NixOS"},{"content":"In August of 2023, I was looking around for a new laptop. At the time, I was running an Alienware laptop with an RTX 3070 in it. However, it is a cumbersome machine with horrible battery life. The great thing was its performance. I needed a machine which was powerful, can run Linux, has great battery life, and portable. I wrote off x86 as S0 sleep mode (Windows Modern Standby) became pervasive, many vendors omitted or improperly handle normal S3 sleep. This led me to an ARM machine. The introduction of compelling ARM-powered laptops led me to select the 2021 MacBook Pro. It has 16GB of RAM and 1TB of storage. To save money, I went with one from Apple\u0026rsquo;s refurbishment service.\nThe Installation Process As soon as my Macbook Pro arrived, I began installing Nix on Darwin. It was a troublesome experience trying to integrate it properly in my Flake config. After a few hours, I was able to get home-manager working with Nix on Darwin. However, I wasn\u0026rsquo;t done yet and I wanted Linux on this machine. So I stumbled upon Thomas Watson\u0026rsquo;s nixos-apple-silicon Flake.\nThe installation went smoothly, after disabling System Integrity Protection and running the Asahi Linux setup script, I was ready to begin. I grabbed my flash drive with Thomas\u0026rsquo;s Asahi NixOS installer on it. From there, installation proceeded like normal for NixOS. I set up an ext4 partition, pull my Flake, and run nixos-install.\nAfter some time of building, I then had NixOS on Apple Silicon. I had my desktop environment setup like how it is on my other machines but on ARM. Unfortunately, audio wasn\u0026rsquo;t working properly at the time so I had to rely on Bluetooth. However, this became less of a problem after months had progressed. I\u0026rsquo;ve been happily running NixOS with Asahi packages on an M1 Pro.\nThe Problems A few problems I ran into with daily driving Asahi NixOS was the system did not have enough memory and not enough storage. I decided to get rid of the replace mode for the Mesa fork and go with an overlay. This would allow me to build my configuration on Garnix, a Nix CI service. However, this had the side effect of causing a mass rebuild of everything requiring Mesa. Not too long after, I had gained access to the Nix community aarch64 machine. I was then able to use it to build the heavy parts of my configuration. The reason why Garnix couldn\u0026rsquo;t build it was either Garnix didn\u0026rsquo;t provide aarch64 at the time or I hadn\u0026rsquo;t gotten my configuration to properly take advantage of Garnix\u0026rsquo;s cache.\nDuring my work with LLVM, I also was experiencing massive usages in memory and storage usage. I had configured my system to use half of the drive while macOS uses the other half. This is so I could have the best of both worlds. Unfortunately, this has restricted how much storage I have so I\u0026rsquo;d often be running the Nix garbage collector. I\u0026rsquo;ve also experienced problems with memory. Due to only having 16GB of RAM and the system using unified memory, there\u0026rsquo;s cases where I can easily run into the out of memory killer triggering and causing jobs to fail. A solution has been to limit the number of jobs. However, these problems are less of a concern after I built my Ampere Altra desktop in July of 2024.\nGaming Many people may think you cannot game on a Macbook. However, that is not the case. There\u0026rsquo;s been many documented cases of people playing Steam games on Apple Silicon machines. Even on macOS, Steam works with Apple\u0026rsquo;s x86 translation layer. However, on Linux we have to use box86. The problem is, Apple Silicon uses a 16k page size due to how the IOMMU is designed. The solution has been to use a project called muvm, formerly called krunvm. However, this tool is new enough that getting it working on NixOS isn\u0026rsquo;t quite possible yet.\nBattery Life One of the big requirements for me when I got this machine was battery life. In macOS alone, the system can last days in sleep which is a great improvement over the 3 hours my Alienware could last in sleep mode. However, it looks like the Asahi project has not fully gained that level of sleep performance (Reference issue AsahiLinux/linux#262 - \u0026ldquo;sleep mode battery improvement\u0026rdquo;). Despite the battery life not being as good as macOS, I can have my machine on battery for 13 hours while alseep. This is a huge improvement over my Alienware but isn\u0026rsquo;t much of a concern as I charge my system overnight and usually have access to power. Although, I mostly have access to an outlet, I like being able to sit on a couch at home or sit on my bed while I work. While working, I can get somewhere between 2 hours and 5 hours of battery life. It is very dependant on what I am working on. If I am building LLVM, I can get 4 full builds and tests of libLLVM to a clang binary and still have 32% battery life. With web browsing and video playback, I can get closer to the 5 or 6 hour life.\nSummary The Asahi project and Thomas Watson have done a great job at getting Linux and NixOS to work well with Apple\u0026rsquo;s ARM chips. The battery life is long enough for me to get plenty of work done while I am not tethered to a wall. The system\u0026rsquo;s performance is quite capable despite being limited by memory and storage. It is my go-to machine and my favorite to use when I don\u0026rsquo;t have to be at a desk. This machine is an example of why ARM is the future.\n","date":"2025-01-17T10:11:00+08:00","permalink":"https://tristanxr.com/post/asahi-nixos/","title":"The Asahi NixOS Experience"},{"content":"Since the early 2000s, multi-core CPUs have been standard in consumer machines. The main advantage of multi-core processors is their ability to run tasks in parallel. If you\u0026rsquo;re not aware, a single CPU core cannot execute multiple instructions simultaneously (except in CPU\u0026rsquo;s with speculative execution, deep pipelining, or SMT). Instead, we rely on schedulers that interrupt the current process and switch it out when it\u0026rsquo;s time for another process to run. However, this method is not entirely optimal, as it can lead to situations where not all processes get enough time. Nowadays, processors often have core counts reaching 10 or more. Many smartphones use octocore processors, meaning they effectively have 8 CPUs within a single CPU. This allows you to run 8 processes on 8 cores, potentially giving 100% execution time to each process if the scheduler permits it. But many of us are not just running 8 processes. Simply booting up a modern OS can result in thousands of processes, though many of these are short-lived or use minimal resources. In a modern OS, processes typically jump between different cores, and those requiring more CPU time are given priority. Balancing workloads on a CPU involves many factors. This post focuses on scaling compiler jobs when using build systems like Ninja, Make, and Nix.\nBinary Optimizations There are many layers to scaling, and the efficiency of your program plays a significant role. Different compilers, even for the same language, can result in varying optimizations that affect runtime performance. All binaries are large without optimizations due to the inclusion of debugging information. Therefore, it is typical to build programs in \u0026ldquo;release\u0026rdquo; mode (using -O3 in C/C++ compilers). This mode maximizes optimizations and minimizes debug information. Another useful technique is compiling with the CPU tune or model set, ensuring the compiler uses the most optimal instructions for the target CPU. CPUs of different architectures, generations, and manufacturers can vary significantly, affecting performance even for programs compiled for the same CPU architecture. CPUs execute instructions in a pipeline, which typically consists of three steps: fetch, decode, and execute. During the fetch stage, the CPU reads the instruction from memory, usually using the program counter register. On modern systems, the CPU often reads from its cache. The CPU then decodes the instruction, setting various control signals. Modern CPUs use microcode to control the timing pulses and control signals. Finally, the CPU executes the instruction, sending various signals based on the decoded instruction.\nHere\u0026rsquo;s an example of how simple programs in x86 assembly can be optimized:\nmov ax, 1 mov bx, 1 add ax, bx This program consists of three instructions: two mov instructions and one add instruction. This simple program takes three clock cycles to complete. However, it can be optimized further:\nmov ax, 1 add ax, 1 Or even more:\nadd ax, 1 This optimization assumes ax is already 1 before the add instruction, reducing the program to a single clock cycle. However, this optimization is dangerous as it assumes the CPU state without checks, potentially leading to incorrect results.\nWorkload Size The size of the workloads, the suitability of the CPU for the workload, and sufficient RAM are crucial. It\u0026rsquo;s better to have a CPU for a specific architecture rather than cross-compiling, as this reduces the bootstrap requirements. Having enough RAM depends on the system\u0026rsquo;s typical usage and the degree of parallelization possible. This distinction will become more apparent as the world moves from x86 to ARM architecture. ARM is known as a RISC (Reduced Instruction Set Computing) architecture, while x86 is a CISC (Complex Instruction Set Computing) architecture. x86 has more instructions, but many are similar to each other. ARM has fewer, more essential instructions, resulting in less complexity, less heat generation, and reduced thermal throttling. This makes ARM ideal for laptops and phones. In my experience with a modern ARM processor (Apple M1 Pro), it outperforms an x86 processor (Ryzen 5 3600 on my desktop). Despite having fewer optimized instructions, having more CPU cores is beneficial. You can only execute instructions so fast, constrained by the silicon design and thermal limits. ARM systems typically run cooler and have more cores, allowing them to handle many processes simultaneously. However, memory remains a critical factor. It\u0026rsquo;s essential to know your workload\u0026rsquo;s RAM requirements and ensure your system has enough RAM to handle peak usage.\n","date":"2024-06-11T19:25:00+08:00","permalink":"https://tristanxr.com/post/scaling-workloads/","title":"Scaling workloads"},{"content":"With packaging software, there will always be cases where software fail to run or build as expected. This is especially common in Nix where it is not a traditional Linux/UNIX environment. For example, Nix does not use the filesystem hierarchy (FHS) which is standard in POSIX. Instead each package has its own directory in the Nix store, also referred to as a local cache, and contains directories such as bin, lib, share, etc. As most software is written to expect the FHS, they can easily break and not run as expected. Due to the Nix store being write-only at build time, it is essentially immutable afterwards. These factors cause many software ranging from LLVM to Google Chrome and Flutter to either not build correctly or not work as intended.\nWhen a patch is required during packaging, it\u0026rsquo;s a good idea to send that patch to the upstream repository. This helps in both preventing the necessity of the patch when packaging future versions of the software, and notifying the upstream contributors that special actions must be taken for a given distro. This offers a collaborative effort to ensure the software builds in one environment but also other environments as well. With my efforts with LLVM, we\u0026rsquo;re trying to upstream patches whenever we perform an update to the git package version of LLVM.\nWhen creating a patch, the easiest way to do it is to utilize the diff command from diffutils. Another way is to use git diff which git provides, this can be piped to a file and added into the directory where your package\u0026rsquo;s build files are. Then you can create a new commit and push to your fork of that software and submit a pull request/merge request. From there, you can easily communicate to the other contributors and developers of the package to ensure the patch works as intended and that it is of good quality. This process may take a while but becomes very collaborative and is often beneficial for everyone.\n","date":"2024-06-10T18:18:00+08:00","permalink":"https://tristanxr.com/post/why-upstreaming-matters/","title":"Why upsteaming patches matters"},{"content":"Since August of 2023, I\u0026rsquo;ve been a daily user of a 14-inch 2021 Apple MacBook Pro (M1 Pro, 16GB RAM) laptop. Thanks to @tpwrules\u0026rsquo;s NixOS Asahi Linux Flake, I was able to set up the laptop to run NixOS. The majority of software have worked perfectly on it and I consider it to be the best Linux laptop for its performance. However, one major issue isn\u0026rsquo;t a hardware issue but a software one. When you see memory sizes on a system, you commonly think about things like the timing, what kind of RAM chips they use, the number of RAM chips in a stick or channel of memory, and so on. Though, this isn\u0026rsquo;t that. This particular issue is one designed into the Asahi Linux kernel and even macOS\u0026rsquo;s Darwin kernel. This would be the page size, the number which dictates the minimum size of a page of memory is. Every modern computer nowadays, since the mid 80\u0026rsquo;s and into the 90\u0026rsquo;s, use something called page memory. This is a technique to efficiently manage memory but it is also used as a security mechanism. Programs can be given permissions to only certain regions of memory via page memory. However, this exact issue is not an issue with the security but the size.\nThe vast majority of users use x86 which utilizes 4k page memory. This size was great when page memory was first introduced along with the Intel 386 in 1985. However, our memory sizes nowadays are vastly larger. This means for a program to allocate something like 1GB of memory, they will need to ask the operating system for a certain number of pages which gets them up to 1GB. On a 4k page size system, this would be about 244,141 pages of memory. However, on a 16k page size system, this would be 61,036. Despite the math being 61035.15625, only whole pages can be allocated. This means the memory allocator used will have to keep that last page for other memory allocations. Between the 4k and 16k page sizes, it is clear that allocating a smaller number of pages can be beneficial when you utilize programs that often are going to be allocating memory sizes beyond 1MB. This can result in a performance improvement as there will be less work the CPU will have to do to ensure the program gets the correct number of pages.\nDue to Asahi Linux using 16k page size memory, this means programs not coded to expect a 16k page size will fail. This is also true for the new Raspberry Pi 5 where the stock OS uses a 16k page size. A few notable programs which break under the 16k page size are Zig, Wine, and Telegram. Telegram for one uses jemalloc which does not ask the operating system for the page size and chooses to pick the size at build time. This causes breakage with prebuilt binaries and distributed versions of the program like the Flatpak or an AppImage. Wine breaks due to it being a runtime environment and so it has to mimick a Windows environment. Zig breaks due to the page size being a constant variable instead of a function, it expects a 4k page size on any ARM system.\nAlthough many programs are broken due to the 16k page size on these modern systems, they will be patched. Asahi Linux has a page on their wiki for broken software which are often attributed to this exact issue. If you do find a piece of software which breaks due to this incompatibility, I can heavily recommend you open an issue on that software\u0026rsquo;s issue tracker and link it to the Asahi Linux\u0026rsquo;s broken software page. In due time, more systems will come out with 64-bit ARM CPU\u0026rsquo;s and many will likely use the 16k page size because of its performance benefits. More broken software will be found but thanks to the developers or contributors, it will be fixed.\n","date":"2024-06-09T18:27:00+08:00","permalink":"https://tristanxr.com/post/why-16k-page-size/","title":"Why 16k page size matters"},{"content":"In programming, technical debt often accumulates over time. It often occurs with legacy code or things which are not maintained often. Recently, I became one of the maintainers for LLVM in Nixpkgs. With LLVM in Nixpkgs, I discovered there was some technical debt which could limit the expansion of LLVM. This also would make it more difficult to package new versions of LLVM. So as a maintainer of LLVM, I made the descision of refactoring all of the version specific subpackage files for LLVM. This work was split up into 7 pull requests and was known as the \u0026ldquo;commonification PR\u0026rsquo;s\u0026rdquo;. My goal was to reduce all the Nix files responsible for the subpackages in LLVM for each version. This ended up making a new directory in Nixpkgs inside of the LLVM specific one which ended up being called \u0026ldquo;common\u0026rdquo;. Some of this work was already done by @Artturin, however my work involved every package in LLVM.\nNow you may be wondering how this was done. I had to figure out which things were common between each package in LLVM across each version and limit certain things based on the version. I ended up using a very useful tool called nix-diff made by @Gabriella439. This tool allowed me to get the differences between my local version of a package and the upstream. I used a very simple wrapper script so I would only have to do something like nix-flake-diff.sh github:NixOS/nixpkgs#llvmPackages_18.clang .#llvmPackages_18.clang.\nWith the nix-flake-diff.sh script, I was able to see how things deviated to prevent Nix from rebuilding. Rebuilds were not acceptable as to prevent any unknown bugs from cropping up and were out of the scope for this project. After 4 days, I was able to reduce the number of files. Each pull request made for each specific LLVM package ended up removing about 1,000 LoC and added under 400 LoC. This resulted in a smaller number of files to manage. It also allows for easily applying changes across all versions without touching other directories.\nNow that it has been more than a month since the pull requests for this project have been merged, Nixpkgs is nearly ready for the next LLVM version. LLVM 19 will be easier to package with the number of files to manage is a lot less. Another reason why LLVM 19 and future versions of LLVM will be much easier to package is because of consistent git updating. I will cover what that entails in the future.\n","date":"2024-06-08T18:16:00+08:00","permalink":"https://tristanxr.com/post/commonifying-llvm-in-nixpkgs/","title":"Commonifying LLVM in Nixpkgs"},{"content":"Hello, I am Tristan Ross. I\u0026rsquo;ve been a Linux user and programmer for over a decade now. As 2023 is coming to a close and 2024 looms ever so closer, I\u0026rsquo;ve been reflecting on the events in the past year. That has led me to the decision of redesigning my website and adding a blog to it. My goal is for other fellow Linux users and programmers to get an understanding of how I do things so they can be inspired. Another goal is for future employers. As I have had been unsuccessful at getting a job after my previous employment in tech, I believe having a blog could show for my skills until I complete my bachelor\u0026rsquo;s degree.\nOne major event I would like to reflect on here is my Japan trip. The cover photo of this post is one I took of a shrine in Kyoto during my two-week vacation. I started my trip by leaving from LAX and landing in NRT. I took Japan Airlines and it was the best airline service I had taken other than Alaska. I got to experience many things that I had been looking forward to. A few of the favorites are the Gundam in Yokohama, Gundam Base, walking around Akihabara, taking the Shinkansen (bullet train), and staying at a Ryokan (traditional Japanese inn). I might make a post at a later date further reflecting on this particular trip.\nBetween my Japan trip and now, not too much has occurred. I\u0026rsquo;ve been continuing to work on ExpidusOS and progressing towards getting my associates degree. Though, I did get a refurbished 2021 Macbook Pro M1 Pro. I decided to then install NixOS which caused me to land on @tpwrules\u0026rsquo;s nixo-apple-silicon Flake. I may make future posts here about my experience with Apple Silicon and even a guide to installing NixOS to your own Apple Silicon device.\nAnyway, that\u0026rsquo;s it for the first post to this website. I\u0026rsquo;ll leave you off with a photo of one of my cats.\n","date":"2023-12-13T16:40:00+08:00","image":"https://tristanxr.com/post/the-beginning/cover_hu4231539671991712483.jpg","permalink":"https://tristanxr.com/post/the-beginning/","title":"The Beginning"}]