Download Reportworq
⬇ Guide PDF

Manage and improve performance#

Distribute the load is about the hardware and where the work runs. This page is about the work itself: why an existing report, job, or form performs the way it does, and what to change.

When to use it. When a pack that used to finish in three minutes now takes twenty, when several people report slowness in the same week, when everything feels slower after an upgrade, or when you have been asked to make something faster and want to know where the time is actually going before you start changing things.

Before you start#

Ask the questions in this order#

Four surfaces answer four different questions, and working from the outside in stops you optimizing the wrong thing. A report that regressed at the same moment as every other report on its node is not a report problem.

Ask Where You learn
1. Is it the instance? Settings ▸ Performance ▸ Distribution Whether many reports moved together, and whether a release or a node explains it
2. Is it this report, over time? The Compare tab on a run's diagnostics Whether there is a single point where this report's typical run time stepped, and whether volume, release, or node moved with it
3. Where did this run's time go? The Performance tab on a run's diagnostics The cost broken down by output, workbook, processing phase, and calculation engine
4. What did it coincide with? The Timeline tab on a run's diagnostics Every span, event, and the memory and CPU trace, drawn on one clock

If contributors rather than reports are the problem, the equivalent funnel is per-server memory on Settings ▸ Performance ▸ Contribution, then a form's footprint in Campaign profiling. See Scale and size a contribution campaign.

1. Rule the instance in or out#

Settings ▸ Performance ▸ Distribution ranks every report against its own baseline and pivots the whole estate by product release and by execution node. It is the only surface that can see across reports, and it is where "did the upgrade do this" is answered.

Choose a window of 30 days, 90 days, or 1 year. Everything on the page, including the baselines, is recomputed inside that window, so a delta on screen is always explained by runs you can see.

Read the five figures first. Runs with telemetry tells you how much of the window is actually measurable, and a low percentage means the page below is thinner than it looks. Releases seen and Nodes seen tell you whether the pivots have anything to compare at all: one release or one node is nothing to compare.

Then read the two pivots at the foot of the page. Three rules govern them, and they are the reason a cell sometimes refuses to give you a verdict:

A refusal to compare is information. It is the page declining to tell you something it cannot honestly know, and it is far more useful than a confident number built on three unlike runs.

The page distinguishes its two empty outcomes, which matters when you are diagnosing rather than browsing. "No runs in this window." means it read the history and found nothing, so widen the window or check that job-history logging is on. "Performance data is unavailable." means the read itself failed, and it shows what went wrong. Those are different problems and the page will not pass one off as the other.

Full field-by-field detail is in Compare performance across reports.

2. Find the moment a report changed#

The Elapsed vs baseline column answers "was the last run normal". That is the wrong question for a report that has been drifting for a fortnight, because every individual run looked fine against a baseline that was itself creeping upward.

The Compare tab asks the other question: across this report's whole history, is there a point where its typical run time changed? It searches for a single step and either finds one or says plainly that there is not one.

The verdict sentence is the whole answer, and it names a cause only when the data shows one. It will tell you whether volume moved across the same split, whether the release differs on either side, and whether the runs moved to a different node. "It got slower" and "it got bigger" are different findings, and this is the surface that separates them.

On a bursting job, use the scope picker to narrow to one variation. A whole-run total moves for reasons that have nothing to do with any one output: a burst list grew, a region was retired, a run was restricted to one recipient to test a fix. Each surviving output stays perfectly comparable with its own past even when the total does not.

See Find when a report got slower.

3. Break one run down#

The Performance tab leads with one sentence naming the dominant cost, then six figures, then a walk you can drill.

Read Elapsed with its volume denominator. Underneath the elapsed time sits the volume the run covered: data points where the run recorded them, otherwise the formula count. This is the first thing to check, because a report doing twice the work in twice the time has not regressed.

Walk from the run down to a phase. One ranked list, largest first, at three levels:

  1. Whole run, listing the outputs it generated. This is where a burst tells you which output is expensive.
  2. One output, listing the workbooks inside it.
  3. One workbook, listing its processing phases. Phases are the last level, and this is where "the PDF took nine minutes" or "the refresh took nine minutes" gets settled.

At workbook level, two tails are listed apart from the ranked phases: phases that ran but cost nothing measurable, and phases that never ran at all. Keeping them separate matters, because "this workbook has no charts" and "charts were free" are different facts about the same run.

What each phase is#

The phase names are the vocabulary the whole surface is written in, so knowing what each one covers is what turns the ranked list into an action. These are the phases Reportworq expects a workbook to have, in roughly the order they run.

Phase What it covers
Open Workbook Loading the source workbook from its report provider, file open and parse
Workbook Initialization Preparation before calculation: hidden-sheet extraction, very-hidden sheet removal, worksheet generation
Generate Worksheets Cloning template sheets per parameter set
Data Refresh The full calculation pass: every datasource calculation service plus the recalculation loop
Recalculate Indirect Formulas INDIRECT and dynamic-formula recalculation after structural edits
Suppress Worksheets Sheet-level suppression driven by RWSHEETSUPPRESS
Rename Worksheets Sheet renaming driven by RWSHEETNAME
Variables Report-scoped variable resolution
Pivot Tables Pivot-table filter application
Charts Refreshing add-in-authored chart and map pictures against the calculated workbook
Images Shape and image refresh across the workbook
Formatting Tab colors, output order, and exception-cell reads
Remove Formulas Formula stripping before save
Workbook Cleanup Deleting worksheets that are not part of the output
Save Workbook Serializing the destination workbook to its output stream
Save PowerPoint Datasource Saving the extra workbook copy kept as a PowerPoint datasource
Script Hooks Custom scripts that run inside report processing

Data Refresh is almost always the largest, and it is the one that contains the recalculation loop, which is why the engine table below it matters more than the phase list. When something other than Data Refresh tops the list, that is the interesting result: a workbook dominated by Charts, Images, or Formatting is paying for its presentation rather than its data, and that is a different conversation with the author.

A few other phases can appear when the work applies to that report, such as parameter application, closing the workbook, or loading a non-Excel source document. They are ranked like any other; only the phases in the table above take part in the "never ran" tail.

The engine table is where the fixable problems are#

Below the walk, the Engines table lists one row per formula family and per calculation service, with Calls, Total, Avg, and Recalc passes.

Recalc passes is the column to read. It says once for an engine that ran a single time, or N of M for one that re-ran during recalculation. An engine reading 5 of 5 on a five-pass workbook ran on every pass, and Reportworq highlights that row when the pass count is high enough for it to be expensive.

That pattern is the single most actionable finding on the whole surface. A data retrieval repeated on every recalculation pass is usually a formula that can be restructured, not an unavoidable cost, and it is invisible from the durations alone: an engine can look cheap per call and still dominate a run because it is trapped in the loop.

Above workbook level the pass counts are folded together from the workbooks in scope, so 5 of 5 there reads as "in the recalculation loop the whole way" rather than as a run-wide total.

See Review a run's performance.

4. See what the time coincided with#

The Timeline tab re-projects the same run onto one clock: execution phases with their varieties nested beneath, per-workbook phase spans, event ticks, and the memory and CPU trace, all sharing one x-axis and one cursor.

It answers a different question from the other tabs. They say where the time went; this says what the time coincided with, which is the only way to see that the third data refresh landed on a memory spike.

Two readings are easy to get wrong:

The tab also says when a cap has hidden detail, such as a very long run whose resource samples were thinned or a run with more spans than the chart draws. Read those notes before concluding that something did not happen.

The levers, and the order to try them#

Work top down. Everything above a line is cheaper and more reversible than everything below it.

Content: change what the work does#

Lever When it applies What to do
A formula family in the recalculation loop The engine table shows N of N on a multi-pass workbook, or a highlighted row Restructure the formula so the retrieval is not re-evaluated on every pass. This is usually the largest single win available.
Data volume grew Elapsed rose and the volume denominator rose with it Not a regression. Decide whether the report needs that volume, and narrow the query or the burst if it does not.
One output dominates a burst The whole-run list is lopsided Treat that output as its own problem. The other outputs are fine and changing them costs effort for nothing.
A phase you did not expect The workbook-level list ranks something surprisingly high The phase names what kind of work it was. Confirm the report actually needs it.

What the breakdown will not tell you. It attributes cost to phases and engines, not to individual design choices, so it cannot confirm that a particular chart, image, or block of formatting costs a given amount. If you suspect one, remove it, run again, and let the before-and-after decide.

Placement and clock: change where and when it runs#

Lever When it applies Where
Split a monolithic job Throughput is not scaling with node count Distribute the load
Raise Tasks per Job A single job's outputs are running more serially than the node can afford Settings ▸ Configuration ▸ Performance ▸ Execution
Pin or exclude with Filter jobs A long job is occupying nodes that serve short runs Settings ▸ Load Balancer, per node
Stagger the schedule The spike is a clock artifact, or a schedule is overrunning its own interval Scheduled Content

Instance: change what the server does#

Lever When it applies Where
Parallel Job Execution and Tasks per Job The server has headroom, or is over-committed against its RAM Settings ▸ Configuration ▸ Performance ▸ Execution
Enable Out of Process Job Execution Should be on. Turn it off only on support advice Settings ▸ Configuration ▸ Performance
Enable Out of Process Reporting Queries Interactive add-in refresh is pressuring the web tier Settings ▸ Configuration ▸ Performance ▸ Reporting
Retention and Compress History Files History or stored output has grown large Settings ▸ Configuration ▸ Performance, and Output retention
Debug Logging left on Always worth checking. It produces very large logs and archives Settings ▸ Configuration ▸ Logging
Recycle Service A long-lived instance benefits from a daily restart Settings ▸ Configuration ▸ Web Server

Contribution: change what a form costs#

Lever When it applies What to do
Make the form smaller Peak cost is high, and bytes per cell is normal Cost is roughly bytes per cell multiplied by cell count, so removing an unused sheet or trimming to the range contributors actually fill removes real cost. Profile before and after.
Manual calculation mode Large forms filled slowly over a day The form stops recalculating on every edit and the server releases an idle session's workbook shortly after the last action that needed it, rebuilding on demand. The trade is that the contributor waits on their next action.
Max Sessions per Worker Workers read At capacity while server memory is comfortable The per-worker session cap is binding, not memory. Raising it lets sessions share a worker baseline, which lowers the per-contributor cost. Default 1, range 1 to 50.
Recycle Worker After Sessions High Served (lifetime) against a short Uptime Workers are recycling often and contributors repeatedly pay a cold start. Default 25; 0 never recycles.
Warm Worker Pool Size Contributors wait on a cold start when they open a form Keeps workers started and waiting. Default 0, meaning no warm pool, so every session pays a start. Range 0 to 50.
Warm Worker Idle Timeout Warm workers are being held longer than a round needs How long an idle warm worker is kept before it exits. Default 30 minutes.

All four are on Settings ▸ Configuration ▸ Performance, under Contribution.

Full arithmetic and the live-round playbook are in Scale and size a contribution campaign.

Prove the change worked#

An improvement you cannot demonstrate is an opinion. The measurement rules make a fair before-and-after straightforward, provided you know them.

Once several runs have accumulated after the change, the Compare tab should find the step you created, in the direction you intended. That is the cleanest evidence available.

Red flags and what they usually mean#

Symptom Usual cause Where to look
Many reports regressed in the same week A release or a node, not the reports Settings ▸ Performance ▸ Distribution, the release and node pivots
One report drifted with no run ever flagged A gradual step the dead band absorbed run by run The Compare tab
Elapsed doubled and so did the volume Not a regression The volume denominator on the Performance tab
One engine dominates with a modest average It is being re-run on every recalculation pass The Engines table, Recalc passes
Occurrences are missing rather than late A schedule overran its own interval past the 30-minute overdue window Scheduled Content, and Distribute the load
Throughput did not improve when a node was added A job runs atomically on one node Distribute the load, job granularity
Analyst refresh is slow while batch throughput is fine Interactive refresh is not distributed and lands on the node holding the session Distribute the load
Contributors are refused a session The 90% memory admission valve Settings ▸ Performance ▸ Contribution
A column of dashes where measurements should be Runs that predate telemetry, or runs held out of the baseline The note under the run list, which states both counts

When to escalate#

Reportworq's own surfaces attribute cost down to a phase and an engine. Below that, the support desk needs the raw material.

Collect it with Settings ▸ Log Diagnostics, which packages application logs from every node, including load-balancer nodes, into a support packet. Say which report and which run you are asking about, since a run's measurements are what support will read first. If you were asked to reproduce the problem with Debug Logging on, turn it off again after the capture: it produces very large logs and archives and is itself a drag on the instance. See Log diagnostics and support packets.

Notes and limits#

Going deeper. For sizing and placement, see Distribute the load. For the full field-by-field reference on each screen, see Compare performance across reports, Review a run's performance, and Find when a report got slower. For the live contribution console, see Contribution processes.

Feedback on this page

Comments, questions, requests, or something missing or unclear? Email us - the page you are on is filled in for you.

Email feedback on this page

Or write to support@reportworq.com directly.