Given that:

  • debug statements consume memory and cpu resources and thus skew performance measurements
  • developer console in profiling perspective shows just events that were logged
  • debug log size is severely limited
  • database inserts are not necessarily immediate

What best practices have you found when performance profiling code on Salesforce?

  • 1
    You're going to need to be more specific. At least two of these statements are incorrect.
    – sfdcfox
    Aug 9 '18 at 22:25
  • @sfdcfox Care to correct me? Thanks!
    – ipavlic
    Aug 9 '18 at 23:50

I think profiling is most useful when you are isolating small chunks of functionality. If you want to know whether it is faster to use List.isEmpty() or List.size() > 0, that sort of question is possible to answer definitively using profiling.

If you take a look at my LimitsProfiler tool, it may give you some ideas. I definitely won't go so far as to say best practice, but I have walked down a similar path and my experience may benefit you.

I profiled LimitsSnapshot.getInstance(), a method which caches all the information given to you by the Limits class. If memory serves, at the time I wrote it, I was able to cache millions of these snapshot instances within a one second interval.

So if you wanted to use my library, you ought to be able to manage a static List<LimitsSnapshot>, and then at the end you can save them, debug them, or whatever you wish.

  • A static class which stores event snapshots in memory and later provides them is where I ended up as well. Thanks for your confirmation!
    – ipavlic
    Sep 1 '18 at 1:22

debug statements consume memory and cpu resources and thus skew performance measurements

Yes, even if you turn off the trace flags, it still has to serialize the parameters, which takes precious CPU time. If you need to get values from your execution at a certain point, use a Checkpoint for debugging. Your Apex Code trace flag must be at least FINER to generate checkpoint logs.

developer console in profiling perspective shows just events that were logged

The Timeline does, but if you press Ctrl/Cmd+P (or Debug > View Log Panels), you can alter your Perspective to include the Stack Tree and Execution Stack panels, which show you the nested function calls (including SOQL, SOSL, DML). You'll get much more valuable information that way.

debug log size is severely limited

In Summer '18, the log size was increased from 2MB to 5MB. 5MB is actually reasonably hard to hit. In fact, the limit was chosen because over 99% of all logs generated don't reach that size (e.g. the salesforce.com engineers took time to figure out a fine balance between system resources and usefulness). If you're still having problems, though, try setting the non-essential trace flags to a lower level. For example, when profiling, you usually only need Profiling to be at FINEST, and you can turn off everything else; you'll get a log that's a few KB at most but tells you exactly where your bottlenecks are.

database inserts are not necessarily immediate

True, but you can account for them. The Profiler includes the amount of time each DML operation takes, as well as queries. You can easily identify any problem database operations with this information.

Try changing your perspective to use the Stack Tree and Execution Stack panels, as they're incredibly useful. Also remember the raw log will have all profiling information at the very end, so you don't need to fumble around to find them. Finally, when profiling, I find it most practical to turn off all other trace flags so that only Profiling is set. This will give you the most realistic expectation of execution time in production. Use the other trace flag logging levels when you're debugging, and get used to Checkpoints, because they will greatly simplify the work you do.

  • I'm likely missing something, but to me it seems that that Stack Tree, Execution Stack and Execution Overview all show just what was logged. If the log does not include Apex information, then I see no profiling information for Apex code. This can also be misleading – if Apex is included but Database is not, then it seems like Apex time dominates database time. So it seems that just Profiling is not enough. And when finer details are included, the log easily overshoots the 5MB (or indeed expanded limits like 10MB).
    – ipavlic
    Aug 29 '18 at 18:25

I found that using a class with static members and methods to store timestamped events and issue a report at the end resolves some issues:

  • Debugging runtime does not have to be used. This avoids:
    • Risk of skewed performance results
    • Known debugging runtime bugs (for example with List.contains, and Set.retainAll)
    • Need to have Finer details to get method entry and exits, which can inflate logs over the limit
  • Profiling can be focused on just those events that are interesting
  • Profiling report data can be formatted and sent to various endpoints

Other issues remain:

  • Profiled code must be littered with event capturing calls
  • Capturing events still spends some time and memory, which is important for low level code

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.