Packages
Multi-surface application runtime for Elixir. One TEA module renders to terminal, browser (LiveView), SSH, and MCP (agents). 30+ widgets, flexbox + CSS grid, AI agent runtime, distributed swarm with CRDTs, time-travel debugging, session recording, sandboxed REPL, and agentic commerce.
Current section
Files
Jump to
Current section
Files
lib/mix/tasks/raxol.perf.ex
defmodule Mix.Tasks.Raxol.Perf do
@moduledoc """
Performance analysis and optimization tools for development.
This task provides various performance analysis capabilities:
## Commands
mix raxol.perf analyze # Analyze current performance
mix raxol.perf profile <module> # Profile a specific module
mix raxol.perf hints # Show performance hints
mix raxol.perf monitor # Start continuous monitoring
mix raxol.perf memory # Memory usage analysis
mix raxol.perf report # Generate performance report
## Examples
# Quick performance check
mix raxol.perf analyze
# Profile terminal operations
mix raxol.perf profile Raxol.Terminal.Buffer
# Start continuous monitoring
mix raxol.perf monitor --interval 30
# Generate detailed report
mix raxol.perf report --format html
"""
use Mix.Task
require Logger
@shortdoc "Performance analysis and optimization tools"
@switches [
format: :string,
interval: :integer,
duration: :integer,
memory: :boolean,
processes: :boolean,
call_graph: :boolean,
help: :boolean
]
@aliases [
f: :format,
i: :interval,
d: :duration,
m: :memory,
p: :processes,
h: :help
]
def run(args) do
{opts, args, _} =
OptionParser.parse(args, switches: @switches, aliases: @aliases)
if opts[:help] do
show_help()
else
ensure_started()
handle_command(args, opts)
end
end
defp handle_command([], _opts), do: handle_command(["analyze"], [])
defp handle_command(["analyze"], _opts) do
Mix.shell().info("🔍 Analyzing current performance...")
analysis = Raxol.Performance.DevProfiler.analyze_current_performance()
Mix.shell().info("\n📊 Performance Analysis Results:")
Mix.shell().info("Memory: #{analysis.memory.total_mb}MB total")
Mix.shell().info("Processes: #{analysis.processes.count}")
if length(analysis.memory.issues) > 0 do
Mix.shell().info("\n⚠️ Issues detected:")
Enum.each(
analysis.memory.issues ++
analysis.processes.issues ++ analysis.system.issues,
fn issue ->
Mix.shell().info(" • #{issue}")
end
)
else
Mix.shell().info("\n✅ No performance issues detected")
end
end
defp handle_command(["profile", module_name], opts)
when is_binary(module_name) do
try do
module = Module.concat([module_name])
if Code.ensure_loaded?(module) do
Mix.shell().info("🔬 Profiling module: #{module}")
profile_opts = build_profile_opts(opts)
# Profile module functions
_result =
Raxol.Performance.DevProfiler.profile(profile_opts, fn ->
# Call some representative functions if they exist
profile_module_functions(module)
end)
Mix.shell().info("✅ Profiling complete")
else
Mix.shell().error("Module #{module} not found or not loaded")
end
rescue
ArgumentError ->
Mix.shell().error("Invalid module name: #{module_name}")
end
end
defp handle_command(["profile"], _opts) do
Mix.shell().error("Usage: mix raxol.perf profile <module_name>")
end
defp handle_command(["hints"], _opts) do
Mix.shell().info("💡 Current Performance Hints:")
if Raxol.Performance.DevHints.enabled?() do
stats = Raxol.Performance.DevHints.stats()
Mix.shell().info(
"Hints system: Enabled (#{stats.total_hints} hints shown)"
)
Mix.shell().info("Uptime: #{Float.round(stats.uptime_ms / 1000, 1)}s")
if map_size(stats.hint_categories) > 0 do
Mix.shell().info("\nHint categories:")
Enum.each(stats.hint_categories, fn {category, count} ->
Mix.shell().info(" #{category}: #{count}")
end)
end
else
Mix.shell().info("Performance hints are not enabled")
Mix.shell().info(
"Enable with: config :raxol, Raxol.Performance.DevHints, enabled: true"
)
end
end
defp handle_command(["monitor"], opts) do
interval = Keyword.get(opts, :interval, 30) * 1000
duration = Keyword.get(opts, :duration, 5) * 1000
Mix.shell().info("📊 Starting continuous performance monitoring...")
Mix.shell().info(
"Interval: #{interval / 1000}s, Duration: #{duration / 1000}s per session"
)
Mix.shell().info("Press Ctrl+C to stop")
Raxol.Performance.DevProfiler.start_continuous(
interval: interval,
duration: duration,
auto_hints: true
)
# Keep the task running
receive do
:never -> :ok
end
end
defp handle_command(["memory"], opts) do
duration = Keyword.get(opts, :duration, 10) * 1000
Mix.shell().info("🧠 Profiling memory usage for #{duration / 1000}s...")
Raxol.Performance.DevProfiler.profile_memory(duration)
end
defp handle_command(["report"], opts) do
format = Keyword.get(opts, :format, "text")
Mix.shell().info("📋 Generating performance report...")
profile_opts = build_profile_opts(opts)
profile_opts =
Keyword.put(profile_opts, :output_format, String.to_atom(format))
# Generate comprehensive report
Raxol.Performance.DevProfiler.profile(profile_opts, fn ->
# Simulate typical workload
simulate_workload()
end)
end
defp handle_command([command], _opts) do
Mix.shell().error("Unknown command: #{command}")
show_help()
end
defp handle_command(command, _opts) do
Mix.shell().error("Invalid command: #{inspect(command)}")
show_help()
end
defp build_profile_opts(opts) do
profile_opts = []
profile_opts =
if duration = opts[:duration] do
Keyword.put(profile_opts, :duration, duration * 1000)
else
profile_opts
end
profile_opts =
if opts[:memory] do
Keyword.put(profile_opts, :memory, true)
else
profile_opts
end
profile_opts =
if opts[:processes] do
Keyword.put(profile_opts, :processes, true)
else
profile_opts
end
profile_opts =
if opts[:call_graph] do
Keyword.put(profile_opts, :call_graph, true)
else
profile_opts
end
profile_opts
end
defp profile_module_functions(module) do
# Try to call some common functions to generate profile data
functions = module.__info__(:functions)
# Look for common patterns and call them safely
Enum.each(functions, fn {name, arity} ->
case {name, arity} do
{:new, 0} ->
try do
apply(module, :new, [])
catch
_, _ -> :ok
end
{:new, 1} ->
try do
apply(module, :new, [%{}])
catch
_, _ -> :ok
end
{:start_link, 0} ->
# Skip GenServer start_link calls in profiling
:skip
_ ->
:skip
end
end)
end
defp simulate_workload do
# Simulate typical Raxol operations for comprehensive profiling
try do
# Terminal operations
if Code.ensure_loaded?(Raxol.Terminal.Emulator) do
emulator = Raxol.Terminal.Emulator.new(80, 24)
Raxol.Terminal.Emulator.process_input(emulator, "Hello, World!")
end
# Buffer operations
if Code.ensure_loaded?(Raxol.Terminal.ScreenBuffer) do
buffer = Raxol.Terminal.ScreenBuffer.new(80, 24)
Raxol.Terminal.ScreenBuffer.write_string(buffer, 0, 0, "Test content")
end
catch
_, _ -> :ok
end
end
defp ensure_started do
# Ensure the application is started for profiling
Mix.Task.run("app.start")
end
defp show_help do
Mix.shell().info("""
Performance analysis and optimization tools for Raxol development.
## Commands
mix raxol.perf analyze # Quick performance analysis
mix raxol.perf profile <module> # Profile specific module
mix raxol.perf hints # Show performance hints status
mix raxol.perf monitor [options] # Start continuous monitoring
mix raxol.perf memory [options] # Memory usage analysis
mix raxol.perf report [options] # Generate performance report
## Options
--format, -f Output format (text, html, json)
--interval, -i Monitoring interval in seconds (default: 30)
--duration, -d Profiling duration in seconds (default: 10)
--memory, -m Include memory profiling
--processes, -p Include process analysis
--call-graph Generate call graph (expensive)
--help, -h Show this help
## Examples
# Quick analysis
mix raxol.perf analyze
# Profile with memory analysis
mix raxol.perf profile Raxol.Terminal.Buffer --memory
# Continuous monitoring every 60 seconds
mix raxol.perf monitor --interval 60
# Generate HTML report
mix raxol.perf report --format html --duration 30
# Memory profiling for 30 seconds
mix raxol.perf memory --duration 30
""")
end
end