How to loop CSV file values using Ultimate Thread Group? - jmeter

I have this links.csv file:
METHOD,HOST,PATH,HITS
GET,google.com,/,7
GET,facebook.com,/,3
I want to create a JMeter test plan using Ultimate Thread Group (UTG) that randomize the hits based on the last column in the CSV above (HITS).
When viewing the results tree, I want to see something like this:
1. google.com
2. google.com
3. facebook.com
4. google.com
5. google.com
6. google.com
7. google.com
8. google.com
9. facebook.com
10. facebook.com
Ideally, I want to set the UTG to use the following settings:
Start Threads Count = sum of all hits in the CSV file (e.g. 7 + 3)
Initial Delay = 0
Startup Time = 60
Hold Load For = 30
Shutdown Time = 0
How to achieve this? I appreciate code samples and screenshots since I'm still new to JMeter.

I can only think of generating a new CSV file out of your original one in order to:
Get the "sum" of "HITS"
Generate a line containing method, host and path per "hit"
In order to achieve this:
Add setUp Thread Group to your Test Plan
Add JSR223 Sampler to the Thread Group
Put the following code into "Script" area:
def entries = new File('/path/to/original.csv').readLines().drop(1)
def sum = 0
def newCSV = new File('/path/to/generated.csv')
newCSV << 'METHOD,HOST,PATH' << System.getProperty('line.separator')
entries.each { entry ->
def values = entry.split(',')
def hits = values[3] as int
sum += hits
1.upto(hits, {
newCSV << values[0] << ',' << values[1] << ',' << values[2] << System.getProperty('line.separator')
})
}
props.put('threads', sum as String)
Use __P() function like ${__P(threads,)} in the Ultimate Thread Group
Use the new "generated" CSV file in the CSV Data Set Config in the Ultimate Thread Group

Related

Jmeter Calculate Value Response Thread Group

how to jmeter calculate response data value
example
Number of thread = 3
Ramp Up = 1
Loop Count = 1
Thread 1 value extract = 3
Thread 2 value extract = 7
Thread 3 value extract = 10
how to get total = 3+7+10 = 20
Add JSR223 PostProcessor after the extractor and put the following code where
props.put('value_' + ctx.getThreadNum(), vars.get('extracted_value'))
Then somewhere in tearDown Thread Group you can use the following expression to get the sum of all values of properties which start with value_
props.entrySet().findAll {prop -> prop.getKey().startsWith('value_')}.collect {prop -> prop.getValue() as int}.sum()
More information about what do these props, ctx and vars mean: Top 8 JMeter Java Classes You Should Be Using with Groovy

Supercollider: Applying FX to a group seems to affect other groups

I have created separate groups on supercollider for each instrument so that I may apply FX, like echo, to the group and only affect one instrument rather than all instruments playing on that sc server.
On the node tree, the echo synthdef correctly appears in the required group (box) and the FX is applied to the instrument in that group, but ALSO incorrectly applying echo to the nodes in other groups on the same server.
What I have noticed is that it affects all higher number groups and not lower number groups. Applying FX (echo) to group 1 or group 2 also applies the same FX to groups 3,4,5,6,7,8, etc., but applying FX to group 8 does NOT seem to affect groups 1,2,3,4,5,6,& 7.
I have tested this on the following systems/versions....
supercollider version (1:3.10.0+repack-1ubuntu2) on ubuntu (Linux
Optiplex-3010 5.4.0-70-generic #78-Ubuntu SMP x86_64 x86_64 x86_64
GNU/Linux)
supercollider version (1:3.10.0+repack-1+rpi1) on Linux raspberrypi
4.19.75-v7l+ #1270 SMP armv7l GNU/Linux
supercollider version (1:3.8.0~repack-2) on Linux advent
5.0.0-32-generic #34~18.04.2-Ubuntu SMP 2019 i686 i686 i686 GNU/Linux
Is this a known bug? Can I make any manual changes to the supercollider code to resolve this? If not, then it will have to be a separate RPi4 for each instrument, underutilising each RPi and increasing project costs significantly.
Regards to all SCcoders,
Phil
Requested code:
(SynthDef(\echo,{|in, out, length = 1, fb = 0.6, sep = 1|
var input = In.ar(in, 2);
var feedback = LocalIn.ar(2);
var output = LeakDC.ar(feedback*fb + input);
LocalOut.ar(DelayC.ar(output, length, sep));
ReplaceOut.ar(out, output);
}).writeDefFile("/home/phil/Supercollider/syndef");)
I instigate the echo via OSC over tcp/ip, but essentially it would be called by:
/s_new s 'echo' i 1028 i 0 i 8 //in this case 1028 is the node for track 8
//and 8 is the SC group
and adjusted by:
/n_set i 1028 s 'fb' f 0.7
UPDATE: In answer to Fizz's comment about...
how I created groups, initially in the startup.scd file and then clear every time the live performance stops and create every time the live performance starts...
oscStream.Clear();
oscStream << osc::BeginBundleImmediate
<< osc::BeginMessage("/g_freeAll") << 1 << osc::EndMessage
<< osc::BeginMessage("/clearSched") << osc::EndMessage
<< osc::EndBundle;
transmitSocketMelody1.Send(oscStream.Data(),oscStream.Size());
oscStream.Clear();
oscStream << osc::BeginMessage("/g_new") << 1 << 0 << 0
<< osc::EndMessage;
transmitSocketMelody1.Send(oscStream.Data(),oscStream.Size());
oscStream.Clear();
oscStream << osc::BeginMessage("/g_new") << 2 << 0 << 0
<< osc::EndMessage;
transmitSocketMelody1.Send(oscStream.Data(),oscStream.Size());
which is the equivalent of...
s.sendMsg(\g_freeAll, 0);
s.sendMsg(\clearSched);
s.sendMsg(\g_new,1,0,0);
s.sendMsg(\g_new,2,0,0);
Order that I create synthdefs...
The echo synthdef (already shown above) is the first created via the supercollider startup.scd file.
Then the sound synthdefs are created in numerical order Piano1, Piano2, Piano3, etc... also via the supercollider startup.scd file.
s.sendMsg(\b_allocRead, 101,"piano-p-c4.wav"); //buffer 101
SynthDef.new("piano1", {|amp=1, freq|
var output,sig,sig2;
sig=PlayBuf.ar(2, 101, freq/523.25, doneAction:2);
sig=sig*amp;
sig = Splay.ar(sig);
Out.ar(0,sig!2);
}).store;
s.sendMsg(\b_allocRead, 111,"piano-p-c5.wav"); //buffer 111
SynthDef.new("piano2", {|amp=1, freq|
var sig;
sig=PlayBuf.ar(2, 111, freq/523.25, doneAction:2);
sig=sig*amp;
sig = Splay.ar(sig);
Out.ar(0,sig!2);
}).store;
The piano synthdefs are played live from the commands..
oscStream_melody1 << osc::BeginMessage("/s_new")
<< "piano1"
<< NextSCNode << 0 << 1
<< "freq" << OscFrequency[OSCOctave][OSCNote]
<< "amp" << Melody1Amplitude*Melody1Volume
<< osc::EndMessage
transmitSocketMelody1.Send(oscStream_melody1.Data(),oscStream_melody1.Size());
oscStream_melody2 << osc::BeginMessage("/s_new")
<< "piano2"
<< NextSCNode << 0 << 2
<< "freq" << OscFrequency[OSCOctave][OSCNote]
<< "amp" << Melody2Amplitude*Melody2Volume
<< osc::EndMessage;
transmitSocketMelody2.Send(oscStream_melody2.Data(),oscStream_melody2.Size());
which is the equivalent of...
s.sendMsg("/s_new","\piano1",1234, 0, 1,"freq",440,"amp", 0.8)
s.sendMsg("/s_new","\piano2",1235, 0, 2,"freq",880,"amp", 0.7)
echo is turned on, modified and off live thus...
s.sendMsg(\s_new,'echo',1001,0,X); //where X is the group to apply to
s.sendMsg(\n_set, 1001,'fb',0.5,'length',1,'sep',1);
s.sendMsg(\n_free, 1001);
but this turns on the echo for all groups with higher numbers, e.g group2, group3, group4 etc.
Whereas if reverb is set on group2 it affects group3, group4, etc but not group1.
Without seeing any code, this is hard to answer, but I wonder if you are using buses? Your instrument group should output to an echo bus and that bus should output to where you wish the sound to go next - another FX bus or to 0.
You'd want to draw a block diagram of your groups, connecting inputs and outputs. Keep in mind that any FX group can take ins from multiple places, but will only have one output. This means you may end up running the same FX synth more than once, for example, if you want echo on groups A and B, but then you want group B to go to a compressor afterwards.
Make sure to declare every bus, give it a good variable name and remember to pass it as an argument on synth creation.

Keep original order of requests in JMeter reports

I use following code to label requests by response times.
if (prev.getTime() > 170 && prev.getTime() < 340) {
prev.setSampleLabel(prev.getSampleLabel() + " > 170")
} else if (prev.getTime() > 340 && prev.getTime() < 4000) {
prev.setSampleLabel(prev.getSampleLabel() + " > 340")
} else if (prev.getTime() > 4000 && prev.getTime() < 8000) {
prev.setSampleLabel(prev.getSampleLabel() + " > 4000")
} else if (prev.getTime() > 8000) {
prev.setSampleLabel(prev.getSampleLabel() + " > 8000")
}
Aggregate report and Summary report contain name of requests in a different order than original one in Thread group. Total number of samples per request is not visible in this way.
JMeter's Aggregate Report and Summary Report listeners always store the Sample Results in their execution order and JMeter executes Samplers upside down (or according to the Logic Controllers)
As you can see, Sampler 4 is the first one because it has been executed first, however it is possible to sort requests by label by clicking the column header since JMeter 3.2):
Another option to sort requests by label is generating HTML Reporting Dashboard

Redis Sorted Set: Bulk ZSCORE

How to get a list of members based on their ID from a sorted set instead of just one member?
I would like to build a subset with a set of IDs from the actual sorted set.
I am using a Ruby client for Redis and do not want to iterate one by one. Because there could more than 3000 members that I want to lookup.
Here is the issue tracker to a new command ZMSCORE to do bulk ZSCORE.
There is no variadic form for ZSCORE, yet - see the discussion at: https://github.com/antirez/redis/issues/2344
That said, and for the time being, what you could do is use a Lua script for that. For example:
local scores = {}
while #ARGV > 0 do
scores[#scores+1] = redis.call('ZSCORE', KEYS[1], table.remove(ARGV, 1))
end
return scores
Running this from the command line would look like:
$ redis-cli ZADD foo 1 a 2 b 3 c 4 d
(integer) 4
$ redis-cli --eval mzscore.lua foo , b d
1) "2"
2) "4"
EDIT: In Ruby, it would probably be something like the following, although you'd be better off using SCRIPT LOAD and EVALSHA and loading the script from an external file (instead of hardcoding it in the app):
require 'redis'
script = <<LUA
local scores = {}
while #ARGV > 0 do
scores[#scores+1] = redis.call('ZSCORE', KEYS[1], table.remove(ARGV, 1))
end
return scores
LUA
redis = ::Redis.new()
reply = redis.eval(script, ["foo"], ["b", "d"])
Lua script to get scores with member IDs:
local scores = {}
while #ARGV > 0 do
local member_id = table.remove(ARGV, 1)
local member_score = {}
member_score[1] = member_id
member_score[2] = redis.call('ZSCORE', KEYS[1], member_id)
scores[#scores + 1] = member_score
end
return scores

ruby multiple loop sets but with limited rows per set

Alrightie, so I'm building an CSV file this time with ruby. The outer loop will run up to length of num_of_loops, but it runs for an entire set rather than up to the specified row. I want to change the first column of a CSV file to a new name for each row.
If I do this:
class_days = %w[Wednesday Thursday Friday]
num_of_loops = (num_of_loops / class_days.size).ceil
num_of_loops.times {
["Wednesday","Thursday","Friday"].each do |x|
data[0] = x
data[4] = classname()
# Write all to file
#
csv << data
end
}
Then the loop will run only 3 times for a 5 row request.
I'd like it to run the full 5 rows such that instead of stopping at Wed/Thurs/Fri it goes to Wed/Thurs/Fri/Wed/Thurs instead.
class_days = %w[Wednesday Thursday Friday]
num_of_loops.times do |i|
data[0] = class_days[i % class_days.size]
data[4] = classname
csv << data
end
The interesting part is here:
class_days[i % class_days.size]
We need an index into class_days that is between 0 and class_days.size - 1. We can get that with the % (modulo) operator. That operator yields the remainder after dividing i by class_days.size. This table shows how it works:
i i % 3
0 0
1 1
2 2
3 0
4 1
5 2
...
The other key part is that the times method yields indices starting with 0.

Resources