Files
agila_open_tool/tools/v/cmd/v2/guiprof/main.v
T

155 lines
4.0 KiB
V

// Copyright (c) 2020-2024 Joe Conigliaro. All rights reserved.
// Use of this source code is governed by an MIT license
// that can be found in the LICENSE file.
module main
import gg
import os
import v2.profiler
fn main() {
// Initialize profiler system
profiler.profiler_init()
// Create application state (on stack, like the working example)
mut app := App{}
// Check command line args for mode
args := os.args
if '--demo' in args {
app.demo_mode = true
app.live_mode = false
init_demo_data(mut app)
} else {
// Default to live mode - read from snapshot file
app.demo_mode = false
app.live_mode = true
}
// Create gg context
app.gg = gg.new_context(
width: window_width
height: window_height
create_window: true
window_title: 'V2 Allocation Profiler'
bg_color: bg_color
frame_fn: frame
event_fn: event_handler
user_data: &app
)
// Run the application
app.gg.run()
}
// frame is the frame callback for gg
fn frame(mut app App) {
draw_frame(mut app)
}
// event_handler handles gg events
fn event_handler(e &gg.Event, mut app App) {
handle_event(e, mut app)
}
// init_demo_data populates the profiler with simulated data for demonstration
fn init_demo_data(mut app App) {
app.demo_mode = true
app.demo_frame = 0
// Create simulated frame and allocation data
app.cached_frames = []profiler.FrameData{cap: 100}
app.cached_allocs = []profiler.AllocRecord{cap: 500}
// Simulate 100 frames of allocation activity
mut total_live := u64(0)
mut peak := u64(0)
mut alloc_idx := 0
mut total_allocs := u64(0)
mut total_frees := u64(0)
for frame_num := 0; frame_num < 100; frame_num++ {
mut frame_data := profiler.FrameData{
frame_num: u64(frame_num)
}
// Simulate some allocations each frame
// More allocations early, fewer later (typical startup pattern)
num_allocs := if frame_num < 20 { 10 - frame_num / 4 } else { 2 + (frame_num % 3) }
for _ in 0 .. num_allocs {
// Random-ish allocation sizes
size := 64 + ((frame_num * 17 + alloc_idx * 31) % 4096)
app.cached_allocs << profiler.AllocRecord{
ptr: unsafe { voidptr(u64(0x1000) + u64(alloc_idx) * 0x100) }
size: size
frame: u64(frame_num)
file: ['main.v', 'parser.v', 'scanner.v', 'types.v', 'gen.v'][alloc_idx % 5]
line: 100 + (alloc_idx % 500)
timestamp: i64(frame_num) * 16_666_667 + i64(alloc_idx) * 1000
freed: false
}
frame_data.new_allocs << alloc_idx
frame_data.new_bytes += u64(size)
total_live += u64(size)
total_allocs++
alloc_idx++
}
// Simulate some frees (but not all - create some "leaks")
// Free some allocations from previous frames
if frame_num > 5 {
num_frees := num_allocs - 1 // Always free slightly fewer than we allocate
mut freed_count := 0
for i := 0; i < app.cached_allocs.len && freed_count < num_frees; i++ {
if !app.cached_allocs[i].freed && app.cached_allocs[i].frame < u64(frame_num - 3) {
// 80% chance to free
if (i * 7 + frame_num * 13) % 10 < 8 {
app.cached_allocs[i].freed = true
app.cached_allocs[i].free_frame = u64(frame_num)
frame_data.freed_idxs << i
frame_data.freed_bytes += u64(app.cached_allocs[i].size)
total_live -= u64(app.cached_allocs[i].size)
total_frees++
freed_count++
}
}
}
}
frame_data.live_bytes = total_live
if total_live > peak {
peak = total_live
}
app.cached_frames << frame_data
}
// Count leaks
mut leak_count := 0
for alloc in app.cached_allocs {
if !alloc.freed {
leak_count++
}
}
// Update stats
app.cached_stats = profiler.Statistics{
live_bytes: total_live
peak_bytes: peak
total_allocs: total_allocs
total_frees: total_frees
leak_count: leak_count
frame_count: 100
}
}
// update_demo_data simulates ongoing activity in demo mode
fn update_demo_data(mut app App) {
// In demo mode, we just use the static simulated data
// For a more dynamic demo, we could add new frames here
app.demo_frame++
}