Y-lib
Loadrunner libraries
y_loadrunner_utils.c
Go to the documentation of this file.
1 /*
2  * Ylib Loadrunner function library.
3  * Copyright (C) 2005-2014 Floris Kraak <randakar@gmail.com> | <fkraak@ymor.nl>
4  * Copyright (C) 2009 Raymond de Jongh <ferretproof@gmail.com> | <rdjongh@ymor.nl>
5  * Copyright (C) 2013-2014 André Luyer
6  *
7  * This program is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU General Public License
9  * as published by the Free Software Foundation; either version 2
10  * of the License, or (at your option) any later version.
11  *
12  * This program is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15  * GNU General Public License for more details.
16  *
17  * You should have received a copy of the GNU General Public License
18  * along with this program; if not, write to the Free Software
19  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
20  */
21 
34 #ifndef _LOADRUNNER_UTILS_C
35 #define _LOADRUNNER_UTILS_C
37 
39 #include "y_core.c"
40 
42 #define _vUserID 0_vUserID_no_longer_exists_please_use_y_virtual_user_id_or_function_y_is_vugen_run
43 #define _vUserGroup 0_vUserGroup_no_longer_exists_please_use_y_virtual_user_group
44 
46 
57 static unsigned long y_hash_sdbm(char* str)
58 {
59  unsigned long hash = 0;
60  int c;
61 
62  if( str == NULL )
63  return NULL;
64 
65  while (c = *str++)
66  hash = c + (hash << 6) + (hash << 16) - hash;
67  return hash;
68 }
69 
70 // --------------------------------------------------------------------------------------------------
71 
72 
99 int y_rand_in_sliding_window(int lowerbound, int upperbound, int rand_max)
100 {
101  int roll;
102 
103  if( (0>lowerbound) || (lowerbound>upperbound) || (upperbound > rand_max) || (rand_max <= 0))
104  {
105  lr_error_message("y_rand_in_sliding_window called with nonsensical arguments: ( 0 <= %d < %d <= %d ) == FALSE",
106  lowerbound, upperbound, rand_max);
107  return -1;
108  }
109 
110  roll = y_rand_between(0, rand_max);
111  if( (roll >= lowerbound) && (roll <= upperbound) )
112  {
113  return 1;
114  }
115 
116  return 0;
117 }
118 
119 
120 // --------------------------------------------------------------------------------------------------
121 
122 
124 
137 int y_rand_between(int lowerbound, int upperbound)
138 {
139  if (lowerbound > upperbound)
140  {
141  lr_error_message("y_rand_between(): lowerbound should be less than upperbound!");
142  return -1; // Note to self: This is a classic case for standard error codes.
143  }
144  return lowerbound + y_drand() * (upperbound - lowerbound + 1);
145 }
146 
147 
163 int y_save_attribute_to_parameter( char* attrib, char* param )
164 {
165  char *tmp = lr_get_attrib_string(attrib);
166  if( tmp == NULL )
167  return -1;
168  else
169  {
170  lr_save_string(tmp, param);
171  return 1;
172  }
173 }
174 
175 // --------------------------------------------------------------------------------------------------
176 
177 
179 
194 int y_save_attribute( char* param )
195 {
196  return y_save_attribute_to_parameter( param, param );
197 }
198 
199 
200 // --------------------------------------------------------------------------------------------------
201 
202 
204 
223 void y_log_rendezvous_result(int result)
224 {
225  char *message;
226  switch( result ) {
227  case LR_REND_ALL_ARRIVED:
228  message = "LR_REND_ALL_ARRIVED - Vuser was released after all the designated Vusers arrived.";
229  break;
230  case LR_REND_TIMEOUT:
231  message = "LR_REND_TIMEOUT - Vuser was released after the timeout value was reached.";
232  break;
233  case LR_REND_DISABLED:
234  message = "LR_REND_DISABLED - The rendezvous was disabled from the Controller.";
235  break;
236  case LR_REND_NOT_FOUND:
237  message = "LR_REND_NOT_FOUND - The rendezvous was not found.";
238  break;
239  case LR_REND_VUSER_NOT_MEMBER:
240  message = "LR_REND_VUSER_NOT_MEMBER - Vuser was not defined in the rendezvous.";
241  break;
242  case LR_REND_VUSER_DISABLED:
243  message = "LR_REND_VUSER_DISABLED - Vuser was disabled for the rendezvous.";
244  break;
245  case LR_REND_BY_USER:
246  message = "LR_REND_BY_USER - The rendezvous was released by the user.";
247  break;
248  default:
249  message = "Unknown rendezvous result code.";
250  }
251 
252  //lr_vuser_status_message("Rendezvous returned: %s", message);
253  lr_log_message("Rendezvous returned: %s", message);
254 }
255 
256 
257 // --------------------------------------------------------------------------------------------------
258 
259 
261 
283 void y_breadcrumb(char *breadcrumb)
284 {
285  lr_message("---------------------------------------------------------------------------------");
286 
287  if( y_is_empty_parameter("breadcrumb") || ((strlen(breadcrumb) == 0)) )
288  {
289  lr_save_string(breadcrumb, "breadcrumb");
290  }
291  else
292  {
293  lr_param_sprintf("breadcrumb", "%s;%s", lr_eval_string("{breadcrumb}"), breadcrumb);
294  }
295 }
296 
297 // --------------------------------------------------------------------------------------------------
298 
299 
307 #define y_breadcrumb_reset() lr_save_string("", "breadcrumb")
308 
309 
310 // --------------------------------------------------------------------------------------------------
311 
312 
314 
330 int y_write_to_file(char *filename, char *content)
331 {
332  long file;
333  int result;
334 
335  lr_log_message("y_write_to_file(%s, %s)", filename, content);
336 
337  if ((file = fopen(filename, "at")) == NULL)
338  {
339  lr_error_message ("Cannot write to file >>%s<<", filename);
340  return -1; // failed to open file...
341  }
342  if (result = fprintf(file, "%s\n", content) <0)
343  {
344  fclose(file);
345  return result; // failed to write to file...
346  }
347 
348  if (fclose(file)!=0)
349  {
350  return -1; // failed to close file...
351  }
352 
353  return 0; // everything worked great!
354 }
355 
357 
374 int y_write_parameter_to_file(char *filename, char *content_parameter)
375 {
376  long fp;
377  char *szBuf, *param;
378  unsigned long nLength;
379  int result = 0;
380  int tmp = 0;
381 
382  lr_log_message("y_write_parameter_to_file(\"%s\", \"%s\")", filename, content_parameter);
383 
384  // Get the parameter content. Tricky because of the possibility of embedded null bytes in there.
385  param = y_get_parameter_eval_string(content_parameter);
386  lr_eval_string_ext(param, strlen(param), &szBuf, &nLength, 0, 0, -1);
387  free(param);
388 
389  // Open the file.
390  if( !(fp = fopen(filename, "wb")) )
391  {
392  lr_error_message("Cannot open file %s for writing!", filename);
393  lr_eval_string_ext_free(&szBuf); // Free the parameter content buffer.
394  lr_abort();
395  return -1; // Errors while opening the file means writing to it is pointless.
396  }
397 
398  // Write the file.
399  if( (result = fwrite(szBuf, 1, nLength, fp)) < nLength )
400  {
401  lr_error_message("Error while writing %d bytes to file: %s ; Only %d bytes were written.", nLength, filename, result);
402  result = -2;
403  // errors during writing should not stop us from closing the file..
404  }
405  else
406  {
407  result = 0;
408  }
409 
410  // Close the file.
411  if( (tmp = fclose(fp)) != 0 )
412  {
413  lr_error_message("Error code %d while closing file %s", tmp, filename);
414  if( result >= 0 ) // if no error occured during writing, fclose() failed, return -3.
415  result = -3;
416  }
417 
418  // Free the parameter content buffer.
419  lr_eval_string_ext_free(&szBuf);
420  return result;
421 }
422 
423 // --------------------------------------------------------------------------------------------------
424 
425 
427 
443 {
444  lr_save_datetime("%Y%m%d,%H%M%S", DATE_NOW, "DATE_TIME_STRING");
445 }
446 
447 
448 // --------------------------------------------------------------------------------------------------
449 
450 
452 
466 int y_workdays_from_today(int workdays)
467 {
468  int weekday, weeksOffset, weekstart;
469  int i = 0;
470  int result = workdays;
471  //int debugOffset = 0;
472 
473  // debugging loop
474  //for(debugOffset = 0; debugOffset < 13; debugOffset++) {
475  // result = debugOffset;
476 
477  //lr_log_message("--- result start %d ---", result);
478 
479  // Determine what day of the week today falls into.
480  lr_save_datetime("%w", DATE_NOW, "weekdayToday");
481  weekstart = atoi(lr_eval_string("{weekdayToday}"));
482  //lr_log_message("--- weekstart = %d ---", weekstart);
483 
484  weeksOffset = result / 5;
485  //lr_log_message("weeksOffset %d", weeksOffset);
486  result += (2 * weeksOffset);
487  //lr_log_message("Adding extra weeks weekends adds up to %d", result);
488 
489  // Determine what day of the week our target day falls into.
490  lr_save_datetime("%w", DATE_NOW + result*(ONE_DAY), "weekdayFuture");
491  weekday = atoi(lr_eval_string("{weekdayFuture}"));
492  //lr_log_message("--- weekday = %d ---", weekday);
493 
494  // Look at each day between the day of the week that our count started on,
495  // and the day of our target date. Shift the target date backwards if we find
496  // a weekend.
497  i = weekstart;
498  do {
499  // Weekend rollover
500  if( i > 6) {
501  i = 0;
502  }
503  // Weekend day found
504  if( i == 0 || i == 6 ) {
505  //lr_log_message("i = %d, adding 1 day", i);
506  result++;
507  }
508  i++;
509  } while( i != (weekday+1) );
510 
511  // Add another day if our target day falls on a saturday.
512  // The search loop accounted for the saturday itself, but saturdays tend to be
513  // followed by sundays ..
514  if ( weekday == 6 ) {
515  //lr_log_message("weekday = %d, adding 1 day", weekday);
516  result++;
517  }
518 
519  //lr_log_message( "############ Final day offset = %d ############", result);
520 
521  //} // end debugging loop
522  return result;
523 }
524 
542 void y_get_disk_space(const char *folder_name, double *available, double *total)
543 {
544  // returned double precision = 53 bit, thus up to 8 EiB (exa byte) it is accurate to the byte.
545  int ret;
546  // struct because were are lacking 64 bit support...
547  struct {
548  unsigned low;
549  unsigned high;
550  } FreeBytesAvailable = {0,0}, TotalNumberOfBytes = {0,0};
551 
552  // require once...
553  static int kernel_dll_loaded = 0;
554  if (!kernel_dll_loaded) {
555  const int le = 0x01020304;
556  // No support for int64_t and __LITTLE_ENDIAN__ in Vugen scripts, so check it here (once):
557  if (sizeof(int) != 4 || *(short*)&le != 0x304) {
558  lr_error_message("This system is not supported, expected 32bit little endian (%d %x)", sizeof(int), *(short*)&le);
559  lr_abort();
560  }
561  ret = lr_load_dll("kernel32.dll");
562  if (ret) {
563  lr_log_error("Unable to load kernel32.dll. Error number %d. Unable to report disk space usage.", ret);
564  lr_abort();
565  }
566  kernel_dll_loaded = 1;
567  }
568 
569  // DiskFreeSpaceEx function http://msdn.microsoft.com/en-us/library/windows/desktop/aa364937(v=vs.85).aspx
570  // The &&GetLastError trick allows to capture the last error before it is erased in the debugger.
571  if (GetDiskFreeSpaceExA(folder_name,
572  available ? &FreeBytesAvailable: NULL,
573  total ? &TotalNumberOfBytes : NULL,
574  NULL) == 0
575  && ((ret = GetLastError())|1)) {
576  char *lpMsgBuf;
577  FormatMessageA(0x1300, NULL, ret, 0, &lpMsgBuf, 0, NULL);
578  lr_error_message("GetDiskFreeSpaceEx returned Windows Error: (%d) %s", ret, lpMsgBuf);
579  LocalFree(lpMsgBuf);
580  // System Error Codes http://msdn.microsoft.com/en-us/library/windows/desktop/ms681381(v=vs.85).aspx
581  // continue to return value of 0.
582  }
583 
584  if (available) {
585  // the total number of free bytes on a disk that are available to the vuser
586  *available = 4294967296. * FreeBytesAvailable.high + FreeBytesAvailable.low;
587  }
588 
589  if (total) {
590  // the total number of free bytes on a disk that are available to the vuser
591  *total = 4294967296. * TotalNumberOfBytes.high + TotalNumberOfBytes.low;
592  }
593 }
594 
604 double y_get_free_disk_space_in_mebibytes(const char* folder_name)
605 {
606  double free_mebibytes;
607  y_get_disk_space(folder_name, &free_mebibytes, NULL);
608  free_mebibytes /= 1048576.;
609  lr_log_message("Free disk space for folder \"%s\": %.0lf MiB)", folder_name, free_mebibytes);
610  return free_mebibytes;
611 }
612 
623 double y_get_free_disk_space_percentage(const char* folder_name)
624 {
625  double available, total;
626  y_get_disk_space(folder_name, &available, &total);
627  available = total ? available / total * 100. : 0.;
628  lr_log_message("Free disk space percentage for folder \"%s\": %.2lf%%", folder_name, available);
629  return available;
630 }
631 
632 
670 int y_read_file_into_parameter(char* filename, char* param)
671 {
672  long pos;
673  char *bytes;
674  long f;
675  lr_log_message("y_read_file_into_parameter(%s, %s)", filename, param);
676 
677  // Open the file.
678  if( (f = fopen(filename, "rb")) == NULL )
679  {
680  lr_error_message("Unable to open file %s", filename);
681  lr_abort();
682  return -1;
683  }
684 
685  fseek(f, 0, SEEK_END);
686  pos = ftell(f);
687  fseek(f, 0, SEEK_SET);
688 
689  bytes = y_mem_alloc(pos);
690  fread(bytes, pos, 1, f);
691  fclose(f);
692 
693  // hexdump(bytes); // do some stuff with it
694 
695  // Save the size for later use
696  lr_param_sprintf("y_byte_size_param_name", "y_size_%s", param);
697  lr_save_int(pos, lr_eval_string("{y_byte_size_param_name}"));
698 
699  lr_save_var(bytes, pos, 0, param);
700  free(bytes); // free allocated memory
701  return pos;
702 }
703 
717 void y_user_data_point(char* param)
718 {
719  lr_user_data_point(param, atof(y_get_parameter(param)) );
720 }
721 
727 {
728  struct _timeb timebuffer;
729  ftime(&timebuffer);
730  return timebuffer.time + (timebuffer.millitm / 1000.);
731 }
732 
733 
739 double y_delay_until(double timestamp)
740 {
741  double current_time = y_get_current_time();
742 
743  if( current_time < timestamp )
744  {
745  double result = timestamp - current_time;
746  lr_force_think_time(result);
747  return result;
748  }
749  else
750  return 0;
751 }
752 
768 #define y_delay_once( delay_in_seconds ) \
769 { \
770  static int delay_done = 0; \
771  \
772  if( !delay_done ) \
773  { \
774  delay_done = 1; \
775  lr_force_think_time(delay_in_seconds); \
776  } \
777 }
778 
779 
820 double y_think_time_for_rampup_ext(int rampup_period, double TPS_initial, double TPS_max, int virtual_users)
821 {
822  static double test_start_time = 0; // Test starttime in seconds since 1 jan 1970.
823  static double previous_time = 0; // Timestamp of the last call to this, after think time.
824  double time_passed; // Elapsed time since test start, in seconds.
825  double response_time; // Elapsed time since previous call.
826  double current_time = y_get_current_time(); // Current time, in seconds since 1 jan 1970.
827 
828  // Initialisation.
829  // On the first call we store the current time as the test start time and the end time of the previous call.
830  if( test_start_time < 1 )
831  {
832  test_start_time = current_time;
833  previous_time = current_time;
834  }
835 
836  // Calculate how much time has passed since test start and the previous call.
837  time_passed = current_time - test_start_time;
838  response_time = current_time - previous_time;
839 
840  // Debugging//
841  lr_log_message("TT calculation: starttime %f, current time %f, previous time %f, virtual_users %d, rampup_period %d",
842  test_start_time, current_time, previous_time, virtual_users, rampup_period);
843 
844  {
845  double TT, TPS_target;
846  double factor = time_passed / rampup_period; // multiplication factor for the target load, based on rampup.
847 
848  if( factor > 1 ) // after rampup load should be stable.
849  factor = 1;
850  else if( factor < 0.03 ) // To prevent extreme thinktimes the first 3% of the rampup thinktime is calculated as if 3% of the time has passed.
851  factor = 0.03;
852 
853  // double TPS_max = virtual_users * (1/response_time); // this is the absolute theoretical maximum, which we aren't using right now.
854  TPS_target = ((TPS_max - TPS_initial) * factor) + TPS_initial; // Apply the ramp up to get the target TPS.
855  TT = (virtual_users / TPS_target) - response_time; // Apply the base formula to get the resulting think time
856 
857  // Debugging.
858  lr_log_message("TT: %f, time_passed: %f, factor %f, response_time %f, TPS_init %f, TPS_max %f, TPS_target %f",
859  TT, time_passed, factor, response_time, TPS_initial, TPS_max, TPS_target);
860 
861  lr_user_data_point("y_thinktime", TT);
862  if( TT > 0 )
863  lr_think_time(TT);
864 
865  // Store the old time in our backup location.
866  //previous_time = current_time;
867  // Do a new time measurement..
868  //ftime(&ts);
869  //current_time = ts.time + (ts.millitm / 1000.);
870 
871  // We measure the response time by comparing previous_time to a new measurement later, but that measurement
872  // will have to be schewed a tad to account for rounding in the windows sleep() call used by lr_think_time().
873  //{
874  //double time_slept = current_time - previous_time;
875  //double deviation = TT - time_slept;
876  //previous_time = current_time + deviation;
877  //lr_log_message("Slept %f sec, deviation %f, current_time %f with deviation added: %f", time_slept, deviation, current_time, previous_time);
878  //}
879 
880  // All of the above can be rewritten to:
881  previous_time = current_time + TT; // Note that the "current time" actually is the timestamp from *before* we slept.
882 
883  return TT;
884  }
885 }
886 
897 double y_think_time_for_rampup(const int rampup_period, double TPS_max)
898 {
899  // These used to be parameters. I've kept them for documentation purposes, but I feel
900  // these defaults are sane enough to allow me to internalize them.
901  const double TPS_initial = 0.1; // Start rampup with this many transactions / sec in total, across all virtual users.
902  const int virtual_users = 1; // How many virtual users the script is using. If you use "1", you can just use TPS / virtual user for the initial target TPS.
903 
904  return y_think_time_for_rampup_ext(rampup_period, TPS_initial, TPS_max, virtual_users);
905 }
906 
916 y_execute_shell_command(char* command, int debug)
917 {
918  const int buffer_size = 10240; // 10 KB;
919  char buffer[10240]; // allocate memory for the output of the command.
920  // Has to be hardcoded because this compiler is stupid about const keywords and I do not want to use #define because of potential side effects. -- FBK
921  long fp; // file/stream pointer
922  int count; // number of characters that have been read from the stream.
923  char *token;
924  char *command_evaluated = lr_eval_string(command);
925 
926  lr_save_string("-- command not yet executed --", "command_result");
927  lr_log_message("Executing command: %s", command_evaluated);
928 
929  fp = popen(command_evaluated, "r");
930  if (fp == NULL) {
931  lr_error_message("Error opening stream.");
932  return -1;
933  }
934 
935  buffer[0] = '\0'; // Clear the buffer before we try to fill it - Prevents the previous command output from showing up in here. -- FBK
936  count = fread(buffer, sizeof(char), buffer_size, fp); // read up to 10KB
937  if (feof(fp) == 0)
938  {
939  lr_error_message("Did not reach the end of the input stream when reading. Try increasing buffer_size.");
940  pclose(fp);
941  return -1;
942  }
943  if (ferror(fp))
944  {
945  lr_error_message ("I/O error during read.");
946  pclose(fp);
947  return -1;
948  }
949  count = fread(buffer, sizeof(char), (sizeof buffer) - 1, fp);
950  lr_save_var(buffer, count, 0, "command_output");
951 
952  // Split the stream at each newline character, and save them to a parameter array.
953  token = (char*) strtok(buffer, "\n"); // Get the first token
954 
955  if (token == NULL) {
956  lr_save_string("", "command_result");
957  }
958  else
959  {
960  lr_save_string(token, "command_result"); // First token saved
961 
962  if(debug)
963  {
964  char param_buf[10]; // buffer to hold the parameter name.
965  int i = 1;
966 
967  while (token != NULL) { // While valid tokens are returned
968  sprintf(param_buf, "output_%d", i);
969  lr_save_string(token, param_buf);
970  i++;
971  token = (char*) strtok(NULL, "\n");
972  }
973  lr_save_int(i-1, "output_count");
974 
975  // Print all values of the parameter array.
976  for (i=1; i<=lr_paramarr_len("output"); i++) {
977  lr_output_message("Parameter value: %s", lr_paramarr_idx("output", i));
978  }
979  }
980  }
981 
982  pclose(fp);
983  return 0;
984 }
985 
1028 int y_errorcheck(int ok)
1029 {
1030  static int enabled = -1;
1031  static int pause_time = 900; // in seconds
1032  static unsigned pacing_limit = 10, abort_limit = -1; // == MAX_INT
1033  static unsigned errorcount = 0; // static means this value will not be reset to zero when a new iteration starts.
1034 
1035  if (enabled < 0) {
1036  // initialize
1037  long tmp, tmp2, nr; char *str;
1038  str = lr_get_attrib_string("errorcheck_enabled");
1039  enabled = str ? // errorcheck_enabled used?
1040  *str ? // and not empty
1041  atoi(str) > 0 // use it's value
1042  : 1 // else errorcheck_enabled used as flag
1043  : 0; // else not set
1044 
1045  str = lr_get_attrib_string("errorcheck_pause_time");
1046  if (!str) str = lr_get_attrib_string("errorcheck_pause_time_seconds"); // old name
1047  if (str && (nr = sscanf(str, "%d:%d", &tmp, &tmp2)) > 0) {
1048  // treat as mm:ss or just seconds
1049  pause_time = nr == 1 ? tmp: tmp * 60 + tmp2;
1050  }
1051 
1052  str = lr_get_attrib_string("errorcheck_limit");
1053  if (str && (nr = sscanf(str, "%u/%u", &tmp, &tmp2)) > 0) {
1054  pacing_limit = tmp;
1055  if (nr == 2) abort_limit = tmp2; // abort_limit is optional
1056  }
1057 
1058  lr_log_message("y_errorcheck() settings: -errorcheck_enabled%s -errorcheck_limit %d/%d -errorcheck_pause_time %u:%02d",
1059  enabled ? "": " 0", pacing_limit, abort_limit, pause_time / 60, pause_time % 60);
1060  }
1061 
1062  if (!enabled) return 0;
1063 
1064  if (ok) errorcount = 0;
1065  else
1066  {
1067  if (errorcount >= abort_limit)
1068  {
1069  lr_error_message("y_errorcheck(): Too many errors occurred. Aborting.");
1070  lr_set_transaction("---TOO MANY ERRORS - ABORTING---", 0, LR_FAIL);
1071  lr_abort();
1072  }
1073 
1074  if (errorcount >= pacing_limit)
1075  {
1076  lr_error_message("y_errorcheck(): Too many errors occurred. Pausing %d seconds.", pause_time);
1077  lr_set_transaction("---TOO MANY ERRORS - THROTTLING LOAD---", 0, LR_FAIL);
1078  y_pace(pause_time); // Prevents overload in case y_pace() is used in this script.
1079  lr_force_think_time(pause_time);
1080  }
1081  if (errorcount) lr_log_message("Number of failed iterations: %d", errorcount);
1082  lr_user_data_point( "y_errorcheck_errorcount", errorcount);
1083  errorcount++;
1084  }
1085 
1086  return 0; // Adding this function to the run logic has the same effect as y_errorcheck(0);
1087 }
1088 
1089 
1090 
1149 double y_pace(double pacing_time_in_seconds)
1150 {
1151  static double test_start_time = 0; // Test starttime in seconds since 1 jan 1970.
1152  static double total_pacing_time = 0; // Running total of requested pacing time.
1153  double current_time = y_get_current_time(); // Current time, in seconds since 1 jan 1970.
1154 
1155  // Initialisation.
1156  // On the first call we store the current time as the test start time and the end time of the previous call.
1157  if( test_start_time < 1 )
1158  {
1159  test_start_time = current_time;
1160  }
1161 
1162  // Debugging
1163  lr_log_message("Pacing calculation: starttime %f, current time %f, total pacing %d", test_start_time, current_time, total_pacing_time );
1164 
1165  {
1166  double time_passed = current_time - test_start_time; // Elapsed time since test start, in seconds.
1167  double pacing_delta = total_pacing_time - time_passed; // How much time still needs to pass to get to the full pacing so far.
1168 
1169  lr_user_data_point("y_pace", pacing_delta);
1170  if( pacing_delta > 0 )
1171  lr_force_think_time(pacing_delta);
1172 
1173  // Now we finally add the pacing time for the *next* iteration to the total.
1174  total_pacing_time += pacing_time_in_seconds;
1175 
1176  return pacing_delta;
1177  }
1178 }
1189 double y_pace_rnd(double min_pacing_time_in_seconds, double max_pacing_time_in_seconds)
1190 {
1191  return y_pace(min_pacing_time_in_seconds + y_drand() * (max_pacing_time_in_seconds - min_pacing_time_in_seconds);
1192 }
1193 
1194 
1196 #endif // _LOADRUNNER_UTILS_C
void ftime(struct _timeb *time)
Documented at http://www.qnx.com/developers/docs/6.5.0/topic/com.qnx.doc.neutrino_lib_ref/f/ftime.html .
int y_workdays_from_today(int workdays)
Calculate the difference in days between today and X workdays into the future.
double y_get_free_disk_space_in_mebibytes(const char *folder_name)
Get the amount of free disk space in the target folder in mebibytes (SI unit)
int y_read_file_into_parameter(char *filename, char *param)
Read the contents of a file into a single parameter.
double y_drand(void)
Generate a random number between 0 <= y_drand() < 1. This supersedes y_rand(). Equal to Math...
Definition: y_core.c:189
int y_errorcheck(int ok)
Errorflood guard. Also known as "the error check".
void y_get_disk_space(const char *folder_name, double *available, double *total)
Get the free disk space on the target folder on the load generator.
size_t fread(void *buffer, size_t size, size_t count, long file_pointer)
Documented at http://www.cplusplus.com/reference/cstdio/fread/.
int y_write_to_file(char *filename, char *content)
Write a string to a file.
int feof(long file_pointer)
Documented at http://www.cplusplus.com/reference/cstdio/feof/.
char * strtok(char *string, const char *delimiters)
Documented at http://www.cplusplus.com/reference/cstring/strtok/.
int fclose(long file_pointer)
Documented at http://www.cplusplus.com/reference/cstdio/fclose/.
char * y_mem_alloc(size_t size)
Ylib wrapper for malloc()
Definition: y_core.c:221
long fopen(const char *filename, const char *access_mode)
Documented at http://www.cplusplus.com/reference/cstdio/fopen/.
Contains core ylib support functions needed for the functioning of the library.
long ftell(long file_pointer)
Documented at http://www.cplusplus.com/reference/cstdio/ftell/.
int atoi(const char *string)
Documented at http://www.cplusplus.com/reference/cstdlib/atoi/.
void y_log_rendezvous_result(int result)
Process the result code of lr_rendezvous() call to log human readable errors.
double y_delay_until(double timestamp)
Delay until a certain time.
#define SEEK_SET
set file offset to offset
Definition: vugen.h:293
size_t fwrite(const void *buffer, size_t size, size_t count, long file_pointer)
Documented at http://www.cplusplus.com/reference/cstdio/fwrite/.
double y_pace(double pacing_time_in_seconds)
Improved implementation of loadrunner pacing.
char * y_get_parameter_eval_string(const char *param_name)
Obtain the string required to fetch the contents of a parameter through lr_eval_string().
Definition: y_core.c:287
long popen(const char *command, const char *access_mode)
Documented at http://man7.org/linux/man-pages/man3/popen.3.html .
double y_pace_rnd(double min_pacing_time_in_seconds, double max_pacing_time_in_seconds)
Improved implementation of loadrunner pacing - with semirandomized pacing.
void y_datetime()
Saves the current date/time into a LR-parameter.
int fprintf(long file_pointer, const char *format_string,...)
Documented at http://www.cplusplus.com/reference/cstdio/fprintf/.
int sprintf(char *buffer, const char *format_string,...)
Documented at http://www.cplusplus.com/reference/cstdio/sprintf/. You should prefer snprintf over s...
int sscanf(const char *buffer, const char *format_string,...)
Documented at http://www.cplusplus.com/reference/cstdio/sscanf/.
y_execute_shell_command(char *command, int debug)
Execute a windows shell command Implements proper error checking.
size_t strlen(const char *string)
Documented at http://www.cplusplus.com/reference/cstring/strlen/.
int y_is_empty_parameter(const char *param_name)
Test if the given parameter is empty or not yet set. (These are two different things..) It would be nice if loadrunner had a builtin for this.
Definition: y_core.c:305
void y_user_data_point(char *param)
Create a user data point for a parameter.
double y_think_time_for_rampup_ext(int rampup_period, double TPS_initial, double TPS_max, int virtual_users)
Ramp up the load by using varying amounts of think time instead of virtual users. ...
int y_write_parameter_to_file(char *filename, char *content_parameter)
Write the content of a parameter to a file.
static unsigned long y_hash_sdbm(char *str)
Create a hash of string input.
unsigned short millitm
Milliseconds. Actual accuracy may be lower.
Definition: vugen.h:226
int ferror(long file_pointer)
Documented at http://www.cplusplus.com/reference/cstdio/ferror/.
int fseek(long file_pointer, long offset, int origin)
Documented at http://www.cplusplus.com/reference/cstdio/fseek/.
#define SEEK_END
set file offset to EOF plus offset
Definition: vugen.h:301
int y_rand_in_sliding_window(int lowerbound, int upperbound, int rand_max)
Generate random number and test if it lies between 2 given boundaries.
char * y_get_parameter(const char *param_name)
Get the content of a parameter and return it as a char *.
Definition: y_core.c:336
void y_breadcrumb(char *breadcrumb)
Keep track of the steps in the script.
double y_think_time_for_rampup(const int rampup_period, double TPS_max)
Ramp up the load by using varying amounts of think time instead of virtual users. For simulating situ...
int y_save_attribute(char *param)
Fetch attribute from vUser&#39;s command lin and store it in a parameter of the same name. This will fetch an attribute from the vUser&#39;s command line (as set in the scenario or in runtime settings (addition attributes)) and stores it in a parameter of the same name. This function is a shortcut to y_save_attribute_to_parameter()
int y_rand_between(int lowerbound, int upperbound)
Create a random number between two boundaries. (the boundaries are included!)
double y_get_current_time()
Get the current time in seconds since 1970, as a double.
double y_get_free_disk_space_percentage(const char *folder_name)
Get the free disk space percentage on the target folder on the load generator.
void free(void *mem_address)
Documented at http://www.cplusplus.com/reference/cstdlib/free/.
time_t time
Time, in seconds, since the Unix Epoch, 1 January 1970 00:00:00 Coordinated Universal Time (UTC)...
Definition: vugen.h:224
int y_save_attribute_to_parameter(char *attrib, char *param)
Fetch attribute from vUser&#39;s command line and store it in a parameter. This will fetch an attribute f...
double atof(const char *string)
Documented at http://www.cplusplus.com/reference/cstdlib/atof/.
Used by ftime. Defined as _timeb (instead of timeb) just as in the on-line Help.
Definition: vugen.h:222
int pclose(long file_pointer)
Documented at http://man7.org/linux/man-pages/man3/pclose.3.html .