Know Your Limits

Manas SinghManas Singh
6 min read

Introduction

Have you ever found yourself debugging a system issue and wished you had a quick way to view all the important OS configuration limits and system information in one place?

Meet Limits: an elegant Python terminal application that provides exactly that functionality with a clean, interactive interface. Limits is a lightweight Python terminal application built with the Textual framework that displays comprehensive OS configuration and limits information. It's designed to be a debugging companion for developers and system administrators who need quick access to system resource information.

Getting Started

Ensure you have Python 3.13+ and uv installed

🖥️ Basic System Info

The application displays a wide range of system metrics organized into logical sections:

  • CPU Information: Physical and logical core counts

  • Memory Information: Total RAM, available memory, and swap space

  • Process Resource Limits: File descriptors, stack size, process limits, virtual memory, and CPU time constraints

  • Filesystem Limits: Maximum filename and path lengths

  • Mounted Filesystems: Disk usage and inode information for all mounted drives

⚡ Alternative Usage

The application can be run in multiple ways:

# With dependency management
uv sync
uv run limits.py

# Debug mode (with textual-dev)
textual run limits.py

# Docker 
docker build -f Dockerfile -t limits:latest .
docker run -it limits:latest

Dependencies

Dependencies are listed in pyproject.toml:

  • Textual: Powers the terminal user interface

    • A clean, tabular display with zebra striping for easy reading

    • Interactive navigation with cursor support

    • Real-time refresh capability

  • psutil: Cross-platform system and process utilities

  • humanize: Makes numbers and dates more human-readable

The application intelligently handles platform differences, providing detailed resource limit information on POSIX systems (Linux, macOS) while gracefully degrading on Windows.

The get_os_info() gathers CPU topology and capabilities, Memory hierarchy (RAM, swap), Process resource constraints, Filesystem characteristics, and Storage device information.

This is an interesting demo whether you're a system administrator looking for a quick diagnostic tool, a developer debugging resource issues, or a Python enthusiast interested in terminal UI development.

Deep Dive

Understating these limits is vital for building robust and performant applications.

1. CPU Information

Physical & Logical Cores

  • Concurrency: The number of cores determines the true level of parallelism an application can achieve. For CPU-bound tasks, this number is critical for tuning thread pools or multiprocessing strategies to maximize performance without causing excessive context switching.

  • Performance Tuning: Knowing the core count helps developers design efficient parallel algorithms and decide on the optimal number of worker processes or threads for services like web servers or data processing jobs.

2. Process Resource Limits

These are per-process limits, often configured at the OS level to ensure system stability by preventing any single process from consuming all available resources.

Max Open Files

This is one of the most common limits hit by network services and database applications. Servers that handle many simultaneous connections (e.g., web servers, message queues) or applications that access many files can easily exhaust this limit, leading to "Too many open files" errors. Developers must monitor this and design their code to manage file descriptors efficiently (e.g., using connection pools).

Max Processes

This limit affects applications that use a multiprocess architecture (e.g., preforking web servers like older versions of Apache or Gunicorn). Exceeding the user's process limit will prevent the application from scaling out by creating new child processes, leading to service degradation.

Stack Size

This defines the amount of memory allocated for a thread's function call stack. Applications with deep recursion or large stack-allocated variables can exceed this limit, causing a stack overflow and an immediate crash. It's a critical consideration for system programmers writing recursive algorithms or complex function call chains.

Virtual Memory (Address Space)

This limits the total virtual memory a process can request. For memory-intensive applications like in-memory databases, caches, or scientific computing tools, this limit can be a bottleneck. Hitting it can cause allocation failures, even if physical RAM is available.

CPU Time Limit

This is a safeguard that kills a process after it has consumed a certain amount of CPU time. While less common in general app development, it's important in multi-user or high-performance computing (HPC) environments to prevent runaway processes from monopolizing CPU resources.

3. Filesystem and Storage Limits

Max Filename & Path Length

Applications that create or manage user-defined file structures must respect these limits to ensure cross-platform compatibility and prevent ENOENT (No such file or directory) or ENAMETOOLONG errors. This is especially important for applications that generate nested directory structures or long, descriptive filenames.

Disk & Inode Usage

  • Disk Space : Running out of disk space is a common cause of application failure. Applications that write logs, temporary files, or store data must have error handling for disk-full scenarios.

  • Inodes : An inode is a data structure that stores information about a file. It's possible to run out of inodes even if disk space is available, especially on systems with a large number of very small files (e.g., mail servers, caches). Applications that create many small files must be aware of this potential limit.

Curious Case of Container Limits

In containers, these are among the most important limits:

  • CPU Limits (Shares, Quota, Period) These control how much CPU time a container gets. Shares provide a relative weight, while quota/period provide a hard cap (e.g., "use 2 CPU cores worth of time every 100ms"). Prevents a single "noisy neighbor" container from starving others of CPU. It's fundamental for multi-tenancy and ensuring predictable performance, but setting limits too low can artificially throttle an application that needs to burst.

  • Memory Limit (memory.limit_in_bytes) The absolute maximum amount of memory a container can use. This is the most critical limit for container stability. If a container's memory usage exceeds this limit, the kernel's Out-Of-Memory (OOM) killer will immediately terminate a process inside it (often the main application), causing the container to crash. Application developers must be acutely aware of their memory footprint relative to this limit.

You run the app with the following options to limit cpu or memory using the Dockerfile :

  • docker run --cpus 4 -it limits:latest or docker run --memory 4g -it limits:latest
🛑
Information looks inaccurate! It displays the same info every time!

Why? The data that is displayed is from the host system. In my case, I have assigned 8 Gb memory and 8 CPUs to my docker engine. This is not what the container is using.

What is the way to fix this? This is left as an exercise for the reader.

0
Subscribe to my newsletter

Read articles from Manas Singh directly inside your inbox. Subscribe to the newsletter, and don't miss out.

Written by

Manas Singh
Manas Singh

14+ Years in Enterprise Storage & Virtualization | Python Test Automation | Leading Quality Engineering at Scale