Skip to content

Lightweight X11/tmux-based token usage visualization for LLM systems. Simulates and monitors token consumption patterns using Unix tools (xload + named pipes) as a local development alternative to CloudWatch/Prometheus metrics. Useful for developing intuition about token usage patterns without deploying full observability stacks.

Notifications You must be signed in to change notification settings

jwalsh/tokenviz

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

15 Commits
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

TokenViz: Token Usage Visualization

Overview

TokenViz provides lightweight token usage visualization for LLM systems using Unix tools. This simulates what would typically be monitored through enterprise observability platforms, making it useful for local development and pattern analysis.

Dashboard Preview

tokenviz_20241106_104613.png

Quick Start

# Launch dashboard (local)
make dashboard

# For container environments
DISPLAY=:1 make dashboard

# View status
make status

# Clean up
make stop

Architecture

System Overview

flowchart TD
    subgraph Generators["Token Generators"]
        G1["Generator 1\n(Random 0-3000)"]
        G2["Generator 2\n(Random 0-3000)"]
        G3["Generator 3\n(Random 0-3000)"]
    end

    subgraph Storage["Storage Layer"]
        L1["/tmp/tokenload/gen1.log"]
        L2["/tmp/tokenload/gen2.log"]
        L3["/tmp/tokenload/gen3.log"]
    end

    subgraph Processing["Aggregation Layer"]
        A1["Aggregator\n(Sum all inputs)"]
        P1["Named Pipe\n/tmp/tokenload_pipe"]
        D1["Data File\n/tmp/tokenload_data"]
    end

    subgraph Display["Visualization Layer"]
        V1["tmux pane 1\nGenerator Logs"]
        V2["tmux pane 2\nTotal Usage"]
        V3["tmux pane 3\nxload Graph"]
    end

    G1 --> L1
    G2 --> L2
    G3 --> L3
    L1 & L2 & L3 --> A1
    A1 --> P1
    A1 --> D1
    L1 & L2 & L3 --> V1
    D1 --> V2
    P1 --> V3
Loading

Data Flow

sequenceDiagram
    participant G as Generators
    participant L as Log Files
    participant A as Aggregator
    participant P as Named Pipe
    participant D as Display

    loop Every Second
        G->>L: Write random token counts
        L->>A: Read latest values
        A->>P: Write sum to pipe
        A->>D: Update display
    end
Loading

Implementation

Configuration

# TokenViz Configuration
SHELL := /bin/bash
.PHONY: all clean test dashboard stop setup generators aggregator test-tmux test-xload status logs kill-all restart

# Check if we're in a container and set DISPLAY accordingly
CONTAINER_CHECK := $(shell test -f /.dockerenv && echo 1 || echo 0)
ifeq ($(CONTAINER_CHECK),1)
	XDISPLAY := :1
else
	XDISPLAY := :0
endif

# Paths
PIPE := /tmp/tokenload_pipe
DATA := /tmp/tokenload_data
LOGDIR := /tmp/tokenload
SESSION := tokenviz

# Default target
.DEFAULT_GOAL := help

help: ## Show this help message
	@echo 'Usage: make [target]'
	@echo
	@echo 'Targets:'
	@grep -E '^[a-zA-Z_-]+:.*?## .*$$' $(MAKEFILE_LIST) | sort | awk 'BEGIN {FS = ":.*?## "}; {printf "\033[36m%-30s\033[0m %s\n", $$1, $$2}'

Core Components

Setup

setup: ## Setup
	@echo "Setting up directories and files..."
	@rm -rf $(LOGDIR) || true
	@mkdir -p $(LOGDIR)
	@rm -f $(PIPE) || true
	@mkfifo $(PIPE)
	@touch $(DATA)
	@for i in 1 2 3; do echo "Initializing gen$$i..." > $(LOGDIR)/gen$$i.log; done

Generators

generators: setup ## Generators
	@for i in 1 2 3; do \
		( \
			while true; do \
				if [ -d "$(LOGDIR)" ]; then \
					echo "gen$$i: $$((RANDOM % 3000))" >> "$(LOGDIR)/gen$$i.log"; \
				else \
					exit 0; \
				fi; \
				sleep 1; \
			done \
		) & \
	done

aggregator: setup ## Aggregator
	@( \
		while true; do \
			if [ -d "$(LOGDIR)" ]; then \
				TOTAL=0; \
				for f in $(LOGDIR)/gen*.log; do \
					if [ -f "$$f" ]; then \
						VAL=$$(tail -n1 "$$f" 2>/dev/null | grep -o '[0-9]*$$' || echo 0); \
						TOTAL=$$((TOTAL + VAL)); \
					fi; \
				done; \
				echo "$$TOTAL" > "$(PIPE)" 2>/dev/null || exit 0; \
				echo "[`date '+%H:%M:%S'`] Total: $$TOTAL" > "$(DATA)" 2>/dev/null || exit 0; \
			else \
				exit 0; \
			fi; \
			sleep 1; \
		done \
	) &

Process Management

Dashboard

dashboard: setup ## Dashboard
	@echo "Starting dashboard with DISPLAY=$(XDISPLAY)..."
	@tmux new-session -d -s $(SESSION) -n 'TokenViz' \; \
		split-window -h \; \
		split-window -h \; \
		select-layout even-horizontal \; \
		send-keys -t 0 "while true; do clear; tail -n 10 $(LOGDIR)/gen*.log 2>/dev/null || echo 'Waiting for data...'; sleep 1; done" C-m \; \
		send-keys -t 1 "while true; do clear; tail -n 10 $(DATA) 2>/dev/null || echo 'Waiting for data...'; sleep 1; done" C-m \; \
		send-keys -t 2 "DISPLAY=$(XDISPLAY) xload -geometry 400x200+100+100 -bg black -fg green -scale 5 < $(PIPE)" C-m \; \
		select-pane -t 0
	@echo "Starting generators..."
	@$(MAKE) generators
	@echo "Starting aggregator..."
	@$(MAKE) aggregator
	@echo "Attaching to session..."
	@tmux attach -t $(SESSION)

Process Control

stop: ## Stop all processes
	@echo "Stopping all processes..."
	@pkill -f "/bin/bash.*while true.*gen" 2>/dev/null || true
	@pkill -f "while true.*TOTAL" 2>/dev/null || true
	@tmux kill-session -t $(SESSION) 2>/dev/null || true
	@rm -f $(PIPE) $(DATA) 2>/dev/null || true
	@rm -rf $(LOGDIR) 2>/dev/null || true
	@echo "All processes stopped"

kill-all: ## Emergency cleanup
	@echo "Emergency cleanup in progress..."
	@ps ax | grep "gen.*RANDOM" | grep -v grep | awk '{print $$1}' | xargs kill -9 2>/dev/null || true
	@pkill -f "while true.*TOTAL" 2>/dev/null || true
	@echo "Emergency cleanup complete"

restart: stop dashboard ## Restart all services

Utility Functions

status: ## Status
	@echo "TokenViz Status:"
	@echo "---------------"
	@echo "Environment: $$([ $(CONTAINER_CHECK) -eq 1 ] && echo 'Container' || echo 'Local')"
	@echo "Display: $(XDISPLAY)"
	@echo "\nGenerator processes:"
	@ps ax | grep "while true.*gen" | grep -v grep || echo "No generators running"
	@echo "\nAggregator process:"
	@ps ax | grep "while true.*TOTAL" | grep -v grep || echo "No aggregator running"
	@echo "\nTmux session:"
	@tmux has-session -t $(SESSION) 2>/dev/null && echo "Session $(SESSION) is running" || echo "No session running"

logs: ## Logs
	@echo "Last 5 lines from each generator:"
	@for i in 1 2 3; do \
		echo "\nGenerator $$i:"; \
		tail -n 5 "$(LOGDIR)/gen$$i.log" 2>/dev/null || echo "No log file"; \
	done
	@echo "\nLast 5 lines from aggregator:"
	@tail -n 5 "$(DATA)" 2>/dev/null || echo "No aggregator data"

test-display: ## Test display
	@echo "Container detection: $(CONTAINER_CHECK)"
	@echo "Using DISPLAY=$(XDISPLAY)"
	@echo "Testing X11 connection..."
	@if DISPLAY=$(XDISPLAY) xdpyinfo >/dev/null 2>&1; then \
		echo "X11 connection successful"; \
	else \
		echo "X11 connection failed"; \
		exit 1; \
	fi

Container Support

Test Display

test-display: ## Test display
	@echo "Container detection: $(CONTAINER_CHECK)"
	@echo "Using DISPLAY=$(XDISPLAY)"
	@echo "Testing X11 connection..."
	@if DISPLAY=$(XDISPLAY) xdpyinfo >/dev/null 2>&1; then \
		echo "X11 connection successful"; \
	else \
		echo "X11 connection failed"; \
		exit 1; \
	fi

Dockerfile

FROM ubuntu:22.04

# Install required packages
RUN apt-get update && apt-get install -y \
    tmux \
    x11-apps \
    xauth \
    make \
    && rm -rf /var/lib/apt/lists/*

# Set up working directory
WORKDIR /app

# Copy application files
COPY . .

# Set display for X11
ENV DISPLAY=:1

# Default command
CMD ["make", "dashboard"]

Cloud Equivalents

AWS Implementation

flowchart LR
    subgraph LLMs["LLM Services"]
        L1["Service 1"]
        L2["Service 2"]
        L3["Service 3"]
    end

    subgraph Queue["Message Queue"]
        Q1["SNS Topic\nToken Usage"]
        Q2["SQS Queue\nAggregation"]
    end

    subgraph Monitor["Monitoring"]
        M1["CloudWatch\nMetrics"]
        M2["CloudWatch\nDashboard"]
    end

    L1 & L2 & L3 --> Q1
    Q1 --> Q2
    Q2 --> M1
    M1 --> M2
Loading

Kafka Implementation

flowchart LR
    subgraph LLMs["LLM Services"]
        L1["Service 1"]
        L2["Service 2"]
        L3["Service 3"]
    end

    subgraph Kafka["Kafka Cluster"]
        K1["Topic: token-usage"]
        K2["Topic: aggregated-usage"]
    end

    subgraph Process["Processing"]
        P1["Kafka Streams\nAggregation"]
    end

    subgraph Monitor["Monitoring"]
        M1["Metrics API"]
        M2["Dashboard"]
    end

    L1 & L2 & L3 --> K1
    K1 --> P1
    P1 --> K2
    K2 --> M1
    M1 --> M2
Loading

Prometheus/Grafana Implementation

flowchart LR
    subgraph LLMs["LLM Services"]
        L1["Service 1\n/metrics"]
        L2["Service 2\n/metrics"]
        L3["Service 3\n/metrics"]
    end

    subgraph Collect["Collection"]
        C1["Prometheus\nServer"]
    end

    subgraph Visual["Visualization"]
        V1["Grafana\nDashboard"]
    end

    L1 & L2 & L3 --> C1
    C1 --> V1
Loading

Contributing

# Contributing to TokenViz

## Development Setup

1. Fork and clone the repository
2. Ensure XQuartz is installed (macOS)
3. Run tests: `make test`
4. Submit PR with clear description

## Container Development

```bash
# Build container
docker build -t tokenviz .

# Run with X11 socket mounted
docker run -v /tmp/.X11-unix:/tmp/.X11-unix tokenviz
```

## Testing
- Run `make test-display` to verify X11 setup
- Run `make test` for full test suite
- Ensure clean shutdown with `make stop`

File Properties

About

Lightweight X11/tmux-based token usage visualization for LLM systems. Simulates and monitors token consumption patterns using Unix tools (xload + named pipes) as a local development alternative to CloudWatch/Prometheus metrics. Useful for developing intuition about token usage patterns without deploying full observability stacks.

Topics

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published

Languages