Old 10-12-2023, 01:30 PM   #1
cfillion
Human being with feelings
 
cfillion's Avatar
 
Join Date: May 2015
Location: Québec, Canada
Posts: 4,937
Default Lua profiler (development tool for ReaScripts)

This is an instrumenting profiler for Lua ReaScripts. It measures function execution time and call frequency. Results are displayed either as a call tree or a flat list. Eight separate profile slots are available for quick A-B comparison.



This script is provided in the form of a library. Search for "Lua profiler" in the ReaTeam Scripts default ReaPack repository. ReaImGui is required as a dependency for the profiler's user interface.

The following data is collected for each function (many columns are hidden in the default view: right-click on the table header to enable them):
  • Source file and line
  • Execution time (with % of total and % of parent)
  • Call count
  • Frame count
  • Time per call (min/avg/max)
  • Time per frame (min/avg/max)
  • Calls per frame (min/avg/max)
Basic usage

The highest-level API for measuring long-running scripts is:

Code:
local profiler = dofile(reaper.GetResourcePath() ..
  '/Scripts/ReaTeam Scripts/Development/cfillion_Lua profiler.lua')
reaper.defer = profiler.defer
profiler.attachToWorld() -- after all functions have been defined
profiler.run()
Select one of the options in the "Acquisition" menu to begin measurement.

run launches the profiler's user interface. defer overrides reaper.defer to capture frame information (should be called exactly once per frame).

Instrumentation

The attachToWorld function above injects instrumentation into all functions found in the global scope, local scope and within tables recursively.

This adds some overhead and a stack level to all of those functions for the profiler to collect call information. It may be desirable to add instrumentation only to select functions instead of everything.

There are several functions provided for this purpose:
  • profiler.attachTo(string var, nil|table opts)
  • profiler.detachFrom(string var, nil|table opts)
  • profiler.attachToLocals(nil|table opts)
  • profiler.detachFromLocals(nil|table opts)
  • profiler.attachToWorld()
  • profiler.detachFromWorld()
attachTo and detachFrom take a variable path as a string. Here are some examples:

Code:
profiler.attachTo('reaper')              -- all functions in the reaper table
profiler.detachFrom('reaper')            -- undoes the previous line
profiler.attachTo('reaper.GetTrack')     -- only this function
profiler.attachTo('gfx`meta')            -- all functions in getmetatable(gfx)
profiler.attachTo('gfx`meta.__newindex') -- getmetatable(gfx).__newindex
profiler.attachTo('foo.bar.baz', { recursive = false })
'opts' is an optional table to customize the variable lookup behavior. Supported keys and default values are:
  • recursive = true
    Whether to dig into subtables (maximum depth is 8).
  • search_above = true
    For {attachTo,detachFrom}Locals only: whether to look into scopes above the caller's.
  • metatable = true
    Whether to also attach to the value's metatable if present.
Intermediate usage

The following API is provided to control when measurements are taken for single-shot scripts or more advanced needs.

start and stop activates and deactivates data acquisition.
Code:
local profiler = ...
profiler.attachTo('foo')
profiler.attachTo('bar')
profiler.run()

profiler.start()
foo()
bar()
profiler.stop()
Use enter and leave to measure a specific block of code (eg. within a larger function). They can be nested. The given string identifier should be unique.
Code:
local foo = 4
bar = 4

profiler.start()
profiler.enter('local')
  for i = 1, 1<<16 do foo = foo * 4 end
profiler.leave()
profiler.enter('global')
  for i = 1, 1<<16 do bar = bar * 4 end
profiler.leave()
profiler.stop()
Advanced usage

There are a few more features exposed to the target script. The defer function shown in the "Basic usage" section above is actually a shortcut for start + stop + frame. frame increments the frame counter and updates per-frame timings.
Code:
profiler.start()
-- user code here
profiler.stop()
profiler.frame()
To start data acquisition over multiple frames when using the defer override:
Code:
profiler.auto_start = true  -- start until manually stopped
profiler.auto_start = 60    -- start for 60 frames then stop automatically
profiler.auto_start = false -- stop
The profiler's user interface can be embedded into any ReaImGui script using showProfile.
Code:
profiler.showProfile(ctx, 'my_profile', width, height)
The run function is a shortcut for creating a ReaImGui context and calling showWindow in a loop.
Code:
local open = profiler.showWindow(ctx, true, flags)
Call reset to clear all data in the selected profile.
Code:
profiler.reset()

Last edited by cfillion; 10-12-2023 at 11:22 PM.
cfillion is offline   Reply With Quote
Old 10-12-2023, 02:50 PM   #2
Meo-Ada Mespotine
Human being with feelings
 
Meo-Ada Mespotine's Avatar
 
Join Date: May 2017
Location: Leipzig
Posts: 6,621
Default

This is huge!
__________________
Use you/she/her.Ultraschall-Api Lua Api4Reaper - Donate, if you wish

On vacation for the time being...
Meo-Ada Mespotine is offline   Reply With Quote
Old 10-12-2023, 04:23 PM   #3
deeb
Human being with feelings
 
deeb's Avatar
 
Join Date: Feb 2017
Posts: 4,812
Default

Quote:
Originally Posted by Meo-Ada Mespotine View Post
This is huge!
true ! amazing cfillion
__________________
🙏🏻
deeb is offline   Reply With Quote
Old 10-12-2023, 11:39 PM   #4
FeedTheCat
Human being with feelings
 
FeedTheCat's Avatar
 
Join Date: May 2019
Location: Berlin
Posts: 2,159
Default

Wow, this is great!

I was surprised to find out that reaper.MIDIEditor_GetActive is even slower than reaper.MIDI_GetRecentInputEvent...
__________________
Featured scripts: REAPER Update UtilityLil ChordboxGridbox/Adaptive gridMX TunerRS5K LinkMIDI Editor Magic Donate💝: PayPal|ko-fi
FeedTheCat is offline   Reply With Quote
Old 10-13-2023, 12:48 AM   #5
bFooz
Human being with feelings
 
Join Date: Jul 2010
Location: Slovakia
Posts: 2,588
Default

w o w
bFooz is online now   Reply With Quote
Old 10-13-2023, 08:33 AM   #6
dsyrock
Human being with feelings
 
dsyrock's Avatar
 
Join Date: Sep 2018
Location: China
Posts: 565
Default

Awesome!
dsyrock is offline   Reply With Quote
Old 10-13-2023, 12:14 PM   #7
Fabian
Human being with feelings
 
Fabian's Avatar
 
Join Date: Sep 2008
Location: Sweden
Posts: 7,416
Default

WoW
Amazing!
__________________
// MVHMF
I never always did the right thing, but all I did wasn't wrong...
Fabian is offline   Reply With Quote
Old 10-14-2023, 04:30 AM   #8
amagalma
Human being with feelings
 
amagalma's Avatar
 
Join Date: Apr 2011
Posts: 3,451
Default

This is great! Thank you very much!!


Here is a small test comparing the various ways of working with reaper arrays in Lua and the results:
__________________
Most of my scripts can be found in ReaPack.
If you find them useful, a donation would be greatly appreciated! Thank you! :)

Last edited by amagalma; 10-14-2023 at 05:28 AM.
amagalma is offline   Reply With Quote
Old 10-14-2023, 05:21 AM   #9
heda
Human being with feelings
 
heda's Avatar
 
Join Date: Jun 2012
Location: Spain
Posts: 7,238
Default

this is amazing. I think it will be very helpful to find performance bugs
thank you !
heda is offline   Reply With Quote
Old 12-04-2023, 09:10 AM   #10
80icio
Human being with feelings
 
Join Date: Mar 2016
Location: Italy
Posts: 322
Default This is amazing

I just started using this script yesterday,
honestly I was scared of what I could find on a script I'm developing,
but in less than 24h my script is already way faster than before.

thanks for developing this, it's huge!

I just wanted to report some discoveries here,

lua math functions vs. scripted math functions

more infos and code snippet on this post
https://forum.cockos.com/showpost.ph...6&postcount=65

Attached Images
File Type: png Screenshot 2023-12-04 at 17.04.51.png (90.9 KB, 337 views)

Last edited by 80icio; 12-04-2023 at 10:00 AM.
80icio is offline   Reply With Quote
Reply

Thread Tools
Display Modes

Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is On
HTML code is Off

Forum Jump


All times are GMT -7. The time now is 02:31 AM.


Powered by vBulletin® Version 3.8.11
Copyright ©2000 - 2024, vBulletin Solutions Inc.