Create a macro say inject_profile inject_profile: proc foo() = discard proc bar() = discard proc baz() = discard Run
In the inject_profile macro you iterate on all items contained in the nnkStmtList, if you find a RoutineNode (proc, template, iterator, macro), you replace the nnkStmtList body with prologue+body+epilogue. However I recommend you go the template way instead, it will give you much more granularity for example this is what I use for [profiling my multithreading runtime](https://github.com/mratsim/weave/blob/2bb0284e5555ec8882412886fb15c948b2826b81/e04_channel_based_work_stealing/profile.nim#L52-L55): > > template profile*(name, body: untyped): untyped {.dirty.} = > profile_start(name) > body > profile_stop(name) > > > Run And [usage](https://github.com/mratsim/weave/blob/330a5113e62f332441397208b1084008a576f83f/e04_channel_based_work_stealing/runtime.nim#L920-L969): proc schedule() = ## Executed by worker threads while true: # Scheduling loop # 1. Private task queue while (let task = pop(); not task.isNil): assert not task.fn.isNil, "Thread: " & $ID & " received a null task function." profile(run_task): run_task(task) profile(enq_deq_task): deque_list_tl_task_cache(deque, task) # 2. Work-stealing request try_send_steal_request(idle = true) assert requested != 0 var task: Task profile(idle): while not recv_task(task): assert deque.deque_list_tl_empty() assert requested != 0 decline_all_steal_requests() assert not task.fn.isNil, "Thread: " & $ID & " received a null task function." let loot = task.batch when defined(StealLastVictim): if task.victim != -1: last_victim = task.victim assert last_victim != ID if loot > 1: profile(enq_deq_task): task = deque_list_tl_pop(deque_list_tl_prepend(deque, task, loot)) have_tasks() when defined(VictimCheck): if loot == 1 and splittable(task): have_tasks() when StealStrategy == StealKind.adaptative: inc num_steals_exec_recently share_work() profile(run_task): run_task(task) profile(enq_deq_task): deque_list_tl_task_cache(deque, task) if tasking_done(): return Run