Which Load‑Testing Tool Performs Best? JMeter, k6, Locust & FunTester Compared
This article benchmarks four load‑testing frameworks—JMeter, k6, Locust, and FunTester—across multiple concurrency levels, measuring CPU, memory, QPS and response time to reveal each tool’s strengths, weaknesses, and scalability limits.
Background
The author previously introduced a performance‑testing framework comparison and now evaluates four popular load‑testing tools—JMeter, k6, Locust, and FunTester—using a simple GET endpoint. The goal is to compare request‑generation capacity and resource consumption under various concurrency levels.
Test Environment
Hardware: 2.6 GHz six‑core Intel Core i7. CPU usage is monitored via Activity Monitor, treating 100 % as one logical thread (1200 % total). Memory usage is also tracked with Activity Monitor.
Test Scripts
Locust (Python 3.8, locust 1.5.3)
from locust import HttpUser, TaskSet, task
class UserBehavior(TaskSet):
@task(1)
def profile(self):
self.client.get("/m")
class WebsiteUser(HttpUser):
tasks = [UserBehavior]
min_wait = 5000
max_wait = 9000After community feedback, the script was updated to use FastHttpUser instead of HttpUser, improving performance roughly twofold.
JMeter (Java 1.8.0_281)
JMeter is run via command line with default settings; the GUI mode is avoided due to instability. The test plan includes the target host (192.168.80.169:12345) and a GET request to /m.
k6 (Golang‑based, script in JavaScript)
import http from 'k6/http';
import { sleep } from 'k6';
export default function () {
http.get('http://192.168.80.169:12345/m');
}FunTester (Groovy, Java SDK)
import com.funtester.config.Constant;
import com.funtester.frame.execute.Concurrent;
import com.funtester.frame.thread.RequestThreadTimes;
import com.funtester.httpclient.ClientManage;
import com.funtester.httpclient.FunLibrary;
import com.funtester.utils.ArgsUtil;
import org.apache.http.client.methods.HttpGet;
class Share extends FunLibrary {
public static void main(String[] args) {
ClientManage.init(10, 5, 0, EMPTY, 0);
ArgsUtil util = new ArgsUtil(args);
int thread = util.getIntOrdefault(0, 200);
int times = util.getIntOrdefault(1, 10000);
String url = "http://192.168.80.169:12345/m";
HttpGet get = getHttpGet(url);
Constant.RUNUP_TIME = 0;
RequestThreadTimes task = new RequestThreadTimes(get, times);
new Concurrent(task, thread, "Local fixed QPS test").start();
testOver();
}
}Test Procedure
Four concurrency levels were used: 10, 50, 100, and 200 threads. For each level the author recorded CPU usage (% of a single thread), memory consumption (MB), achieved QPS, and average response time (ms). The target service was a simple Moco server exposing a single GET endpoint.
Results & Observations
10 Threads
FunTester showed the lowest CPU (28.82 %) and high QPS (2282) with moderate memory (385 MB).
k6 achieved the highest QPS (2302) with low memory (78 MB) but slightly higher CPU (53.54 %).
JMeter and Locust had higher memory footprints and lower QPS.
50 Threads
k6 and FunTester again delivered the highest QPS (≈9800) with modest memory usage.
JMeter’s CPU and memory rose sharply (120 % CPU, 777 MB memory) and its QPS was only 3594.
Locust lagged behind with QPS ≈1425 and high response time (27 ms).
100 Threads
Only k6 and FunTester remained viable; k6 reached 12631 QPS with 199 % CPU, FunTester 13604 QPS with 226 % CPU.
Both tools showed similar response times (~7 ms), indicating the system was approaching its performance ceiling.
200 Threads
k6 achieved 15354 QPS with 240 % CPU and 240 MB memory; FunTester produced 14940 QPS but consumed 432 % CPU and 428 MB memory.
Response time increased noticeably for both tools, confirming the bottleneck.
Key Takeaways
At low concurrency (<100 threads) FunTester consumes slightly less CPU, but k6 scales better under high load thanks to Go’s lightweight goroutine model.
JMeter exhibits unstable port usage and high error rates under heavy load, making it less suitable for large‑scale tests.
Locust’s CPU consumption is relatively high and its QPS lower, leading the author to drop it from further testing.
Increasing JVM heap size did not noticeably improve FunTester’s performance, highlighting the efficiency of Go‑based k6.
Conclusion
For single‑machine load testing, k6 provides the best overall balance of CPU efficiency, memory usage, and throughput, especially at high concurrency. FunTester remains a capable alternative for moderate loads, while JMeter and Locust are less competitive in this specific scenario.
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.
