skip to content

Why can a JMeter CSV results file hold more rows than samplers times iterations?

level: middleimportance: should knowfreq 37%

answer

  1. Children get rows, not just parents
  2. One property, on by default
  3. CSV flattens what XML nests
  4. Child labels gain a numeric suffix
  5. Parent totals already include the children

basics

~10 s

Sub-samples get rows of their own. jmeter.save.saveservice.subresults defaults to true, so every child result a sampler produced is written as an extra flat row after its parent, relabelled parentLabel-0, parentLabel-1 and so on.

solid answer

~40 s

A sampler can produce child results, and `jmeter.save.saveservice.subresults` — `true` by default — tells JMeter to save them. In CSV there is nowhere to nest, so each child is written as its own flat row immediately after the parent's, recursively for children of children. Unless the plan is in Functional Test Mode or `subresults.disable_renaming` is set, JMeter also relabels each child `<parentLabel>-<index>` counting from zero, which is why a kept file contains labels such as `Home Page-0` that appear nowhere in the `.jmx`. The parent row is not a summary of separate rows: it already absorbs its children's byte counts and its end time is stretched to the last child, so summing `bytes` or counting rows over the whole file double-counts. Setting the property to `false` drops the child rows entirely.

code

csv · 4 lines
csv
timeStamp,elapsed,label,responseCode,responseMessage,threadName,dataType,success,failureMessage,bytes,sentBytes,grpThreads,allThreads,URL,Latency,IdleTime,Connect
1551783627191,842,Home Page,200,OK,Thread Group 1-1,text,true,,54210,940,1,1,https://shop.example/,131,0,14
1551783627340,96,Home Page-0,200,OK,Thread Group 1-1,text,true,,11902,310,1,1,https://shop.example/app.css,44,0,0
1551783627438,120,Home Page-1,200,OK,Thread Group 1-1,bin,true,,29740,310,1,1,https://shop.example/logo.png,51,0,0

go deeper

for a junior

Know that a results file can carry more rows than you configured samplers, and that the extra rows come from sub-samples rather than from a bug.

for a middle

Name jmeter.save.saveservice.subresults, state that it defaults to true, and explain that CSV flattens children into their own rows while XML nests them.

for a senior

Catch the double counting: a parent's bytes and elapsed already cover its children, so any aggregate taken over every row of a kept file is wrong unless the rows were filtered first.

for a principal

Set the expectation that a result file ships with the setting that produced it. A row count means nothing across teams until everyone's subresults choice is the same or recorded.

You come back to a results file months after the run, count its rows, and the number does not match the plan. Almost always the answer is sub-samples: results that hang off a parent sample rather than standing beside it. ## Where sub-samples come from Several JMeter features attach child results to a parent sample. The ones you meet most often: - an HTTP sampler that fetched embedded resources, each resource becoming a child; - a request that followed redirects, each hop becoming a child; - a Transaction Controller configured to generate a parent sample, with the samplers under it as children. How each of those features works is owned by its own topic. What matters here is the consequence for the file: those results exist, and by default they are saved. ## Flat rows in CSV, nested elements in XML `jmeter.save.saveservice.subresults` defaults to `true`. The two writers honour it differently: 1. **CSV** prints the parent's line, then walks the children and prints each one as a full row of its own, then recurses into their children. The nesting is lost — a child row looks exactly like a top-level sample. There is a depth guard: recursion stops beyond ten levels, so a pathologically deep tree silently loses its deepest rows. 2. **XML** writes each child as a nested element inside its parent's element, so the structure survives and a reader can tell parent from child. ## The relabelling that confuses people later When a child is attached, JMeter renames it to the parent's label, a hyphen, and a zero-based index: `Home Page`, `Home Page-0`, `Home Page-1`. This is the sub-result naming policy, and it is on unless the Test Plan is in Functional Test Mode or the property `subresults.disable_renaming` is set to `true`. It is the reason a `label` column can contain names that appear nowhere in the plan. ## Why you cannot just add the columns up When a child is attached to a parent, JMeter *accumulates* into the parent: - the parent's `bytes` and `sentBytes` grow by the child's; - the parent's end time is extended to the child's end time, so the parent's `elapsed` spans all of them. So the parent row and its child rows overlap by design. Summing `bytes` across every row in a file that has sub-results counts them twice. Counting rows and calling it *requests issued* over-counts wherever a parent was not itself a request — a Transaction Controller's generated parent sample, for instance. That trap is invisible on the day, when everyone knows the plan, and expensive six months later when nobody does. ## Deciding what to do about it | Setting | Effect on the file | When it fits | |---|---|---| | `subresults=true` (default) | Every child gets a row | You need per-resource or per-hop detail | | `subresults=false` | Only top-level samples are written | The file is evidence for the transactions, not their parts | | XML output | Children nested under parents | You want the structure preserved for a reader | Whichever you pick, write it down next to the file. A row count is only meaningful against a known `subresults` setting, and the file itself does not record which one was in force.

  • Where do labels like Home Page-0 come from, given no such sampler exists in the .jmx?
    From JMeter's sub-result naming policy. When a child result is attached, it is relabelled to the parent's label plus a hyphen and a zero-based index. The policy is active unless the Test Plan runs in Functional Test Mode or `subresults.disable_renaming=true` is set.
  • Can you total the bytes column of a JMeter CSV JTL to get the traffic the run generated?
    Not if the file contains sub-results. A parent's byte counts already include its children's, so summing every row counts them twice. Either filter to top-level rows, or write the file with `jmeter.save.saveservice.subresults=false` in the first place.
  • What happens to a JMeter sub-result tree nested more than ten levels deep in a CSV file?
    The CSV writer stops recursing past ten levels, so anything deeper is simply not written. It is not an error and nothing is logged for it; the rows are just absent from the file.

saying these in an interview costs you the question

  • Assumes one row always means one sampler execution
  • Sums the bytes column across parent and child rows
  • Thinks CSV preserves the parent-child relationship
  • Believes extra labels mean the plan was edited
  • Says subresults defaults to off