Standard Deviation

Just started using k6 and loving it. Except for one missing feature which is standard deviation. I’ve spent 2 hours trying to implemnent it on http_req_duration but to no avail. please help

I don’t understand your question but maybe can I help you. The http_req_duration is used for Total time for the request. It’s equal to http_req_sending + http_req_waiting + http_req_receiving (i.e. how long did the remote server take to process the request and respond, without the initial DNS lookup/connection times).

I understood wich you need get custom metrics, in documentation K6 have a documentation about this.

Explain it to me better so I can help you :slightly_smiling_face:

Hi there. Thank you for the response. Basically every request has a different http_req_duration and what I need is its standard deviation which is basically the variation of the extreme results from the average. K6 does provide the average but not standard deviation which is weird since every other load testing tool I’ve used for e.g Jmeter does give it.
I did try using Trend to create a custom metric but standard deviation requires a sum of all the http_req_duration which k6 does not provide. I tried doing a custom implementation but as I understand shared variables are not possible due to the concurrent nature of VUs and without them I don’t think its possible

Hi there. Ok I understand your question. Really in K6 not exist the stdev, but in my work I calculated the Standard Deviation using NodeJs. I execute o comando k6 run --out json=test_results.json teste.js which create a json file with all of the http_req_duration. After I process the json file and get the standart deviation. Below I share with you my code.

The good of K6 is a liberty for created other codes to get another values, metrics and generate data

const fs = require('fs');

// Function to calculate the standard deviation
function calculateStdDev(values) {
    if (values.length === 0) return 0;

    // Calculate the mean
    const mean = values.reduce((acc, val) => acc + val, 0) / values.length;

    // Calculate the standard deviation
    const squaredDiffs = values.map(val => Math.pow(val - mean, 2));
    const avgSquaredDiff = squaredDiffs.reduce((acc, val) => acc + val, 0) / values.length;
    return Math.sqrt(avgSquaredDiff);
}

// Function to process the data and extract http_req_duration values
function processMetrics(jsonData) {
    let durations = [];

    // Iterate through the data and extract the 'http_req_duration' values
    jsonData.forEach(item => {
        if (item.metric === 'http_req_duration' && item.type === 'Point') {
            durations.push(item.data.value); // Extract the duration value
        }
    });

    return durations;
}

// Main function
function main() {
    // Read the JSON file generated by k6 line by line
    fs.readFile('test_results.json', 'utf8', (err, data) => {
        if (err) {
            console.error('Error reading the JSON file:', err);
            return;
        }

        // If the file contains multiple JSON objects (one per line), process them separately
        let jsonData = [];
        const lines = data.split('\n');

        lines.forEach(line => {
            try {
                if (line.trim()) {
                    // Parse each line of JSON content
                    jsonData.push(JSON.parse(line.trim()));
                }
            } catch (parseError) {
                console.error('Error parsing the JSON line:', parseError);
            }
        });

        // Process the data to extract the durations
        let durations = processMetrics(jsonData);

        if (durations.length > 0) {
            // Calculate the standard deviation of the durations
            let stdDev = calculateStdDev(durations);
            console.log(`The standard deviation of http_req_duration is: ${stdDev}`);
        } else {
            console.log('No http_req_duration values found in the JSON.');
        }
    });
}

// Run the script
main();

To run this code just enter the command node script.js

Let me know if it worked :slightly_smiling_face:

1 Like

This does indeed work. Thanks! is there a way I could integrate this with my tests? as in I don’t have to run it separately after the test runs just to calculate the deviation. Maybe somehow adding it to into the summary?

I believe that you need to use the handleSummary Custom summary | Grafana k6 documentation, but I wasn’t able to save the list of http_req_interation in time of execution, maybe you can work :slightly_smiling_face:

A tip, maybe you need to use SharedArray to save the list of http_req_interation, or create all of the logic in the handleSummary as in the example Custom summary | Grafana k6 documentation

import http from 'k6/http';

// use example function to generate data
import k6example from 'https://raw.githubusercontent.com/grafana/k6/master/examples/thresholds_readme_example.js';
export const options = { vus: 5, iterations: 10 };

export function handleSummary(data) {
  console.log('Preparing the end-of-test summary...');

  // Send the results to some remote server or trigger a hook
  const resp = http.post('https://httpbin.test.k6.io/anything', JSON.stringify(data));
  if (resp.status != 200) {
    console.error('Could not send summary, got status ' + resp.status);
  }
}

In my job I used before the execution to presented a final report.

Let me know if it works :slightly_smiling_face:

That’s what I first tried. But apparently SharedArrays cannot be modified after creation so I’m stuck at a deadend with this. Anyways I’ll mark this as solved. Thank you!

Just try this format, I believe its work!

import http from 'k6/http';

// use example function to generate data
import k6example from 'https://raw.githubusercontent.com/grafana/k6/master/examples/thresholds_readme_example.js';
export const options = { vus: 5, iterations: 10 };

function calculateStandardDeviation(values) {
  const mean = values.reduce((a, b) => a + b, 0) / values.length;
  const squaredDiffs = values.map(value => Math.pow(value - mean, 2));
  const variance = squaredDiffs.reduce((a, b) => a + b, 0) / values.length;
  return Math.sqrt(variance);
}

export function handleSummary(data) {
  console.log('Preparing the end-of-test summary...');

  // Example: Calculate standard deviation of HTTP request durations
  const requestDurations = data.metrics.http_req_duration.values; // metric to use
  const durationsArray = Object.values(requestDurations); // extract as array
  const stdDeviation = calculateStandardDeviation(durationsArray);

  console.log(`Standard Deviation of request durations: ${stdDeviation.toFixed(2)}ms`);

  // Send the results to some remote server or trigger a hook
  const resp = http.post('https://httpbin.test.k6.io/anything', JSON.stringify(data));
  if (resp.status != 200) {
    console.error('Could not send summary, got status ' + resp.status);
  }
}

This won’t work either as data.metrics.http_req_duration.values is just an object:

{
        "p(90)": 142.380461,
        "p(95)": 154.601834,
        "avg": 118.15383435785641,
        "min": 97.614864,
        "med": 113.773443,
        "max": 193.534749
      }

which isn’t enough for calculation of std deviation. I guess it’s just not possible to calculate it directly using k6. However the solved solution is a viable alternative if someone else comes across this issue

I understand @hammad1029, I tried to help you, but this problem with is good to trye :sweat_smile:
I’m sorry for don’t help you more.

The post-execution alternative is easier to create

Maybe, is intersting you try to create a Issue in Github/K6 for create a std deviation metrics in K6.

1 Like