k6 community forum

K6 take too much time to load

Hi,

I’m suppose to load test,10 minutes long session after I convert the .har file into js file is about 1.5 MB size. k6 take more than 20 minutes to load it, Please let me what wrong with it, how do I overcome this problem.

Hi @arunaxp,
The load time of k6 is … more or less proportional to the size of the script and the number of VUs. I could recommend reducing the size of the script but this will be hard in your case :slight_smile:.

In the current master there is a new feature compatibility-mode which disables some ECMAScript supportwhich also reduces memory usage and loading times (1 2) (both pretty significantly in the cases we have tested).
But in order to get your script to work you will need to change it which is probably going to be way too time consuming so I would recommend using my k6-es6 project ( :wink: ). With it you can do … not great but pretty good transformation to something compatibility-mode will be able to execute.

Please if you do try those, share some numbers :wink: and don’t forget you will need to run master (either through the docker label master or by building it yourself)

Hi @mstoykov,

Thank you for your reply. I just got it to work. buy my existing code has

recordings.find(x => x.key.

which I used to manipulate arrays, if I have

–compatibility-mode

it throw an error ? why is that ?

: Line 39:38 Unexpected token > (and 2 more errors)

I just tested and k6-es6 through webpack converts calls to find to something that k6 does understand
my code :

var a = [1,2,3,4,5];
export default function() {
    console.log(a.find(b => b> 3));
}

which replaces main.js in k6-es6
I do
npm run-script webpack
And then

$ k6 run --compatibility-mode base build/app.bundle.js

          /\      |‾‾|  /‾‾/  /‾/
     /\  /  \     |  |_/  /  / /
    /  \/    \    |      |  /  ‾‾\
   /          \   |  |‾\  \ | (_) |
  / __________ \  |__|  \__\ \___/ .io

  execution: local
     output: -
     script: build/app.bundle.js

    duration: -,  iterations: 1
         vus: 1, max: 1

INFO[0000] 4
    done [==========================================================] 1 / 1

    data_received........: 0 B 0 B/s
    data_sent............: 0 B 0 B/s
    iteration_duration...: avg=481.32µs min=481.32µs med=481.32µs max=481.32µs p(90)=481.32µs p(95)=481.32µs
    iterations...........: 1   0/s
    vus..................: 1   min=1 max=1
    vus_max..............: 1   min=1 max=1

my build/app.bundle.js is quite big though at 1217 lines of unminified javascript so … hard to share :wink:

1 Like

Hi @mstoykov,

Thank you for your comments, It really helps.
I have tested with compatibility mode as you mentioned.

If I changed the --compatibility-mode into base and also I converted my script into es5, It really fast , Ex : one of my small script I had to wait around 52 seconds to start K6, but base mode it ran without any delay.

But, It would not be practical to convert my whole script into ES5, so I used extended mode, I cannot see any fast of execution (it take 52 second to start).

Do I understand that k6-es6 doesn’t transform something in a way that base compatibility-mode can run it?
If so can you provide me with a small example? You can try to run babel against your script (similar to how I run webpack against it), as this is what k6 does and then use the resulting output directly with base. But I would prefer it if we can make k6-es6 handle whatever it currently doesn’t for you;).
Apart from compatibility-mode there really is nothing much you can do at this point to make it faster :(. Your script is big and with the additional processing that extended has it just takes time, Especially with many VUs

Hi @mstoykov,

What I mean was I had to convert my es6 scripts to es5 as follows ‘https://docs.k6.io/docs/javascript-compatibility-mode’ in-order to I used the base mode.

Hope my code would help

//---------
import {group,check,sleep} from 'k6';
import {Trend,Gauge,Counter} from 'k6/metrics';
import {recordings} from '../out/recordings.js';
import http from "k6/http";

//assign session key for each VU
let mxKey = '';


const baseURL = "https://xxxxxxlocalnet";
const orgAdminKey = 'aaaaaa';


let myTrend = new Trend('my_trend', true);
let error_trend = new Trend("error_trend");
var resources_trend = new Trend("resources_trend", true);
var profile_trend = new Trend("profile_trend", true);
var counter_profiles = new Counter("counter-profiles");
var profile_vu_gauge = new Gauge("profile_vu_gauge");

const categories = {
  VECTOR: {
      url: 'resources/vector'
  },
  SEARCH: {
      url: 'feature/search'
  },
  REFINE: {
      url: 'resources/vector/refine'
  }
};

let newPageLoad = recordings.find(x => x.key.endsWith('new-page-load'));

let newRecordings = recordings.filter(e => !e.key.endsWith('new-page-load'));
var profileCounters = newRecordings.map(function(r) {
  return {
      profile: r.key,
      counter: new Counter('Counter-' + r.key)
  }
});

let max = 50;
export let options = {
  // hosts: {
  //   "test.loadimpact.com": "1.2.3.4"
  // },
  //stress tesing
  stages: [
    
    { duration: '10m', target: 1 },
    // { duration: '2m', target: 50 },
    // { duration: '15m', target: 50 },
    // { duration: '2m', target: 75 },
    // { duration: '15m', target: 75 },
    // { duration: '2m', target: 100 },
    // { duration: '15m', target: 100 }
  ],

  //load test
  // stages: [
  //     { duration: '60m', target: 300 },
  // ],

  //spike test
  // stages: [
  //   { duration: "1m", target: 50 },
  //   { duration: "29m", target: 50 },
  //   { duration: "2m", target: 50 },
    // { duration: "28m", target: 200 },
    // { duration: "3m", target: 300 },
    // { duration: "27m", target: 300 },
    // { duration: "10m", target: 0 }
  // ],

  // thresholds: {
  //   http_req_duration: ["avg<100", "p(95)<200"]
  // },
  noVUConnectionReuse: true,
  userAgent: 'MyK6UserAgentString/1.0',
  discardResponseBodies: true,
};

function createTrend(res, profile) {
  Object.keys(res).map(k => {
      let r = res[k];
      if (r.url.endsWith(categories.VECTOR.url)) {
          resources_trend.add(r.timings.duration, {
              profile: profile,
              resource: categories.VECTOR.url
          });
      } else if (r.url.endsWith(categories.SEARCH.url)) {
          resources_trend.add(r.timings.duration, {
              profile: profile,
              resource: categories.SEARCH.url
          });
      } else if (r.url.endsWith(categories.REFINE.url)) {
          resources_trend.add(r.timings.duration, {
              profile: profile,
              resource: categories.REFINE.url
          });
      }
  });
}

function preprocess(req, key) {
  req.map(r => {
      if (!r.params) r.params = {};
      if (!r.params.headers) return;
      if (!r.params.cookies) return;
      Object.keys(r.params.headers).map(n => {
          if (n.toLowerCase() == 'authorization') {
              r.params.headers[n] = key;
          }
      });
  });
  return req;
}

function createErrorTrend(result, res, profile) {
  if (!result) {
      error_trend.add(1, {
          fail_url: res["url"],
          response_code: res["status"],
          profile: profile
      });
  }
}

let opts = {
  preprocess: preprocess,
  createTrend: createTrend,
  createErrorTrend: createErrorTrend,
};

export function setup() {
  profileCounters.map(x => {
      x.counter.add(0, {
          profile: x.profile,
          vu: 0,
          iter: 0
      });
  });
  counter_profiles.add(0);
}

export default function() {
  if (mxKey == '') {
      let res = getSession();
      if (res != null) {
          mxKey = JSON.parse(res.body).key;
      }
  }

  console.log(`VU: ${__VU}  -  ITER: ${__ITER}  -  KEY: ${mxKey}`);

  var weighted_key = selectWeighedKey(newRecordings);
  let recording = newRecordings.find(x => x.key == weighted_key);

  profileCounters.find(x => x.profile == recording.key).counter.add(1, {
      profile: recording.key,
      vu: __VU,
      iter: __ITER
  });

  counter_profiles.add(1, {
      profile: recording.key,
      vu: __VU,
      iter: __ITER
  });

  console.log(`FILE: ${recording.key}`);

  if (Math.random() > 0.5) {
      group(newPageLoad.key, function() {
          newPageLoad.method(opts, newPageLoad.key, mxKey);
      });
  }

  group('profile-' + recording.key, function() {
      let st = Date.now();
      recording.method(opts, recording.key, mxKey);
      myTrend.add(Date.now() - st, {
          profile: recording.key
      });

      profile_trend.add(Date.now() - st, {
          profile: recording.key
      });

      profile_vu_gauge.add(1, {
          profile: recording.key
      });

      profileCounters.find(x => x.profile == recording.key).counter.add(-1, {
          profile: recording.key,
          vu: __VU,
          iter: __ITER
      });

      counter_profiles.add(-1, {
          profile: recording.key,
          vu: __VU,
          iter: __ITER
      });
  });


  // group('idle-time', function() {
  //     sleep(Math.floor(Math.random() * 30 + 10));
  // });

}
//select weighted key
var selectWeighedKey = function(list) {
  
  var weightTotal = list.reduce(function(accumulator, currentValue) {
      return accumulator + currentValue.weight;
  }, 0);

  let items = [];
  list.map(item => {
      let per = Math.round((item.weight / weightTotal) * 100);

      for (let index = 0; index < per; index++) {
          items.push(item.key);
      }
  })

  let randVal = rand(0,items.length-1);
  return items[randVal];
};

var rand = function(min, max) {
  return Math.floor(Math.random() * (max - min + 1)) + min;
};

//get session
function getSession() {
  try {
      var date = new Date();
      let data = {
          "acl": {
              "read": [],
              "write": [],
              "remove": [],
              "roles": [
                  "USER"
              ],
              "grants": [
                  "world",
                  "registered",
                  "1:\u0000",
                  "1:7OETjhrDEDmSqL1vM6k6Fw"
              ]
          },
          "data": {
              "referenceId": "1:LkDwlgWKEDmdlb2OwBmW9A"
          },
          "expires": date.setDate(date.getDate() + 1)
      };

      let headers = {
          "Content-Type": "application/json",
          "Accept": "application/json",
          "Authorization": orgAdminKey
      };

      // Send get session request
      let res = http.post(baseURL + "/resources/session/token", JSON.stringify(data), {
          headers: headers,
          responseType: 'text'
      });
      let result = check(res, {
          "status is 200": (r) => r.status == 200
      });

      if (result)
          return res;
      else
          return null;
  } catch (error) {
      return null;
  }
}

//----

Hi,

I have tested compatibility mode base, it is really fast and I would like to ask newer versions would continues with this option?
This option help me on

  • reduced k6 loading time.(tested with 7MB .js file)
  • reduced request failure counts

Thank you @mstoykov

Hi @arunaxp,
Yes, the compatibility-mode is here to stay and will be released in 0.26.0 … which is due to release for the last few weeks, and I hope it will be next week ;).
I did try to convert your script yesterday but had a lot of problems … some of which are likely to be an issue with k6 instead of just with my webpack setup (k6-es6). As such it seems that at least for now if the script isn’t really simple it will need some manual transformation ;( .

Can you share your some numbers ? How was it starting before, how fast is it starting now ? How many failures were before and how many are now? Also maybe how much the memory and/or CPU usage has gone down :slight_smile:
Thanks and glad I could help

Hi @mstoykov,
for the moment I don’t have stat with me, stable version of k6 take more than 10 minutes to load 1.5 MB file, I couldn’t run such a file. Today I tested with 7MB file it load and started on k6 within couple of seconds.
I will get back to you with stat later. :+1:

1 Like