155 lines
4.0 KiB
V
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++
|
|
}
|