Profiling Code Performance and Arc XP
Fast and performant sites encourage readers to spend more time on them and boost page ranking. Dealing with a site that is performing below those high expectations can be frustrating. This article provides tips and tools to help diagnose and improve your site's codebase to be more performant.
Note
Arc XP is specifically designed to be most performant in production environments only. Slower responses in staging or local environments are expected behavior.
Logs
The first step in profiling your code's performance is log forwarding, which you can request from Arc XP Customer Support. Find more information on log forwarding in PageBuilder Engine Log Forwarding. Once you have these logs, use the following tips to read them.
The built-in console logger (
console.log
) is a good general-purpose solution, but anything you write tostdout
will also appear in the logs.Node.js provides a built-in package (
perf_hooks
) for measuring code's runtime performance. More detailed documentation can be found here.Use distinct, easily searchable messages. “
[fetch-timer] example.tld/extension 31ms”
is easier to find than “31
”.
Sample profiler code
One approach to profiling code is to use timers to measure how long a function takes to finish running. Below is a sample implementation for this type of profiler:
const { performance } = require('perf_hooks'); /** * Profile synchronous code. */ const profile = (name, fn) => { return (...args) => { const start = performance.now(); const result = fn(...args); const end = performance.now(); console.log(`[sync-profiler(${name})]: started at ${start}ms, ended at ${end}ms, took ${end - start}ms`); return result; }; }; profile.sync = profile; /** * Profile asynchronous code. */ profile.async = (name, fn) => { return async (...args) => { const start = performance.now(); const result = await fn(...args); const end = performance.now(); console.log(`[async-profiler(${name})]: started at ${start}ms, ended at ${end}ms, took ${end - start}ms`); return result; }; };
If you have a function that seems to perform poorly, you can use a profiler to measure it with the profiler functions:
/** * This function will not resolve until at least one second has passed. */ const asyncFunction = async () => { await new Promise((resolve) => setTimeout(resolve, 1000)); return 'Waited for at least one second!'; }; /** * This function will count to one-billion. */ const syncFunction = () => { for (let i = 0; i < 1E9; ++i) { // do nothing } return 'Counted to one-billion!'; }; /** * This function will wait for a full second, and then it will write * the profiler's log message to the console. */ const profiledAsyncFunction = profile.async('asyncFunction', asyncFunction); /** * This function will count to one-billion, and then it will write the * profiler's log message to the console. */ const profiledSyncFunction = profile.sync('syncFunction', syncFunction); /** * This line will run the profiled async function. */ profiledAsyncFunction(1000).then(console.log); /** * This line will run the profiled sync function. */ profiledSyncFunction(1E7);
This type of feedback is useful for finding performance problems and measuring your progress toward resolving them.
You can find more examples of code profiling in the following articles:
Node.Js V14.20.0 Documentation
Additional resources
PageBuilder Engine Log Forwarding
How to Request Tracing in Content Sources with PageBuilder Engine