Spaces:
Running
Running
Jae-Won Chung
commited on
Commit
•
315ec00
1
Parent(s):
7aacedb
Add load testing
Browse files
spitfight/colosseum/client.py
CHANGED
@@ -27,7 +27,7 @@ class ControllerClient:
|
|
27 |
"""Initialize the controller client."""
|
28 |
self.controller_addr = controller_addr
|
29 |
self.timeout = timeout
|
30 |
-
self.request_id = str(
|
31 |
|
32 |
def fork(self) -> ControllerClient:
|
33 |
"""Return a copy of the client with a new request ID."""
|
|
|
27 |
"""Initialize the controller client."""
|
28 |
self.controller_addr = controller_addr
|
29 |
self.timeout = timeout
|
30 |
+
self.request_id = str(uuid4()) if request_id is None else str(request_id)
|
31 |
|
32 |
def fork(self) -> ControllerClient:
|
33 |
"""Return a copy of the client with a new request ID."""
|
tests/colosseum/controller_load_test.py
ADDED
@@ -0,0 +1,112 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
import os
|
2 |
+
import time
|
3 |
+
import random
|
4 |
+
import itertools
|
5 |
+
import multiprocessing as mp
|
6 |
+
|
7 |
+
import tyro
|
8 |
+
|
9 |
+
from spitfight.colosseum.client import ControllerClient
|
10 |
+
|
11 |
+
CONTROLLER_ADDR = os.environ["COLOSSEUM_CONTROLLER_ADDR"]
|
12 |
+
|
13 |
+
PROMPTS = [
|
14 |
+
"What is Deep Learning?",
|
15 |
+
"Write a poem about life.",
|
16 |
+
"What is the basics of Rust?",
|
17 |
+
"What is Python's GIL?",
|
18 |
+
"What are Go channels and how do they compare with Rust flume channels?",
|
19 |
+
"What is the difference between a list and a tuple in Python?",
|
20 |
+
"How do I use Python's asyncio.wait?",
|
21 |
+
"How do I accurately measure the execution time of a function in Python?",
|
22 |
+
"How do I use Python's multiprocessing module?",
|
23 |
+
"What is Python's built-in dataclasses module?",
|
24 |
+
"How is Python's async/await different from Rust's async/await?",
|
25 |
+
"What is Hugging Face Transformers?",
|
26 |
+
"Tell me about your capabilities.",
|
27 |
+
"When is your knowledge cutoff, and what does it mean?",
|
28 |
+
"Explain Machine Learning in simple terms.",
|
29 |
+
"Write a song that welcomes new students to the University of Michigan.",
|
30 |
+
"Explain how to use the Pydantic library with a single code block.",
|
31 |
+
"Write a poem about Jae-Won Chung, God of Computer Science.",
|
32 |
+
"Write a poem about the University of Michigan.",
|
33 |
+
"How do I get my new AI startup funded?",
|
34 |
+
"Explain the notion of zero copy in programming.",
|
35 |
+
"Explain the notion of zero knowledge proofs.",
|
36 |
+
"Explain the notion of zero trust in cybersecurity.",
|
37 |
+
"What is a monad in functional programming?",
|
38 |
+
"What is a monad in category theory?",
|
39 |
+
"How are monads implemented in both Haskell and OCaml?",
|
40 |
+
"What is the difference between a monad and a functor?",
|
41 |
+
"What is the difference between a monad and a monoid?",
|
42 |
+
"How are monads used in Rust?",
|
43 |
+
"What is a good name for a software library that makes ML energy efficient?",
|
44 |
+
"What would be some good naming criteria for a tech startup?",
|
45 |
+
"What is the opposite of democracy? Explain in detail.",
|
46 |
+
"Why are people scared to be contacted by the IRS?",
|
47 |
+
"What is fingerstyle guitar?",
|
48 |
+
"How do I practice and play fingerstyle guitar?",
|
49 |
+
"What is the difference between fingerstyle and classical guitar?",
|
50 |
+
"What is the difference between classical and flamenco guitar?",
|
51 |
+
"What is the difference between classical and jazz guitar?",
|
52 |
+
"Explain the basics of the Django web framework.",
|
53 |
+
"Explain the basics of the Flask web framework.",
|
54 |
+
"Explain the basics of the FastAPI web framework.",
|
55 |
+
"I really need to pee. What should I do?",
|
56 |
+
"Why would one use Python's abc module?",
|
57 |
+
"Explain Python type annotations and why they are useful.",
|
58 |
+
"How do I create an immutable list in Python?",
|
59 |
+
"How do I create a mutable tuple in Python?",
|
60 |
+
"When does dropping out of a Computer Science PhD program make sense?",
|
61 |
+
"What is the difference between a PhD and a Masters in Computer Science?",
|
62 |
+
"How are software engineers and software developers different?",
|
63 |
+
"Hi",
|
64 |
+
"What's up",
|
65 |
+
"How are you?",
|
66 |
+
"What am I supposed to type here",
|
67 |
+
"Is indoor vaping legal?",
|
68 |
+
"What are the key points of the 14th amendment?",
|
69 |
+
"I'm new to the US. What are some social taboos I should be aware of?",
|
70 |
+
] * 2
|
71 |
+
|
72 |
+
|
73 |
+
def request(prompt: str) -> tuple[str, str, str, str, float]:
|
74 |
+
time.sleep(random.random() * 5)
|
75 |
+
client = ControllerClient(CONTROLLER_ADDR, timeout=30)
|
76 |
+
|
77 |
+
response_a, response_b = "", ""
|
78 |
+
start_time = time.monotonic()
|
79 |
+
for resp_a, resp_b in itertools.zip_longest(
|
80 |
+
client.prompt(prompt, index=0),
|
81 |
+
client.prompt(prompt, index=1),
|
82 |
+
):
|
83 |
+
if resp_a is not None:
|
84 |
+
response_a += resp_a
|
85 |
+
if resp_b is not None:
|
86 |
+
response_b += resp_b
|
87 |
+
|
88 |
+
latency = time.monotonic() - start_time
|
89 |
+
return client.request_id, prompt, response_a, response_b, latency
|
90 |
+
|
91 |
+
|
92 |
+
def main(concurrency: int = len(PROMPTS), logfile: str = "load_test_results.csv"):
|
93 |
+
latencies = []
|
94 |
+
|
95 |
+
start_time = time.monotonic()
|
96 |
+
with mp.Pool(processes=concurrency) as pool:
|
97 |
+
for request_id, prompt, response_a, response_b, latency in pool.imap_unordered(request, PROMPTS):
|
98 |
+
latencies.append(latency)
|
99 |
+
print(f"Request ID {request_id} finished, {latency=:.2f}s")
|
100 |
+
|
101 |
+
total_time = time.monotonic() - start_time
|
102 |
+
average_latency = sum(latencies) / len(latencies)
|
103 |
+
requests_per_second = len(latencies) / total_time
|
104 |
+
print(f"Total time: {total_time:.2f}s")
|
105 |
+
print(f"Average latency: {average_latency:.2f}s")
|
106 |
+
print(f"Requests per second: {requests_per_second:.2f}")
|
107 |
+
with open(logfile, "a") as f:
|
108 |
+
f.write(f"{concurrency},{total_time},{average_latency},{requests_per_second}\n")
|
109 |
+
|
110 |
+
|
111 |
+
if __name__ == "__main__":
|
112 |
+
tyro.cli(main)
|