arvnoodle commited on
Commit
0d89d1c
·
verified ·
1 Parent(s): 0236623

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +66 -28
app.py CHANGED
@@ -3,37 +3,56 @@ import plotly.graph_objects as go
3
  import pandas as pd
4
  import numpy as np
5
 
6
- def calculate_runpod_cost(
7
  requests_per_hour,
8
  execution_time_per_request,
9
  active_cost_per_second,
10
  flex_cost_per_second,
11
- cold_start_penalty=30,
12
- active_request_percentage=0.5
 
13
  ):
14
- # Calculate monthly requests
15
- monthly_requests = requests_per_hour * 24 * 30
 
 
16
 
17
- # Split requests between active and flex workers
18
- active_requests = monthly_requests * active_request_percentage
19
- flex_requests = monthly_requests * (1 - active_request_percentage)
20
 
21
- # Calculate active worker cost
22
- active_cost = active_requests * execution_time_per_request * active_cost_per_second
23
 
24
- # Calculate flex worker cost (including cold start penalty)
25
- flex_cost = flex_requests * (execution_time_per_request + cold_start_penalty) * flex_cost_per_second
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
26
 
27
- # Total monthly cost
28
  total_monthly_cost = active_cost + flex_cost
29
 
30
  return {
31
  "monthly_requests": monthly_requests,
32
- "active_requests": active_requests,
33
  "flex_requests": flex_requests,
34
  "active_cost": active_cost,
35
  "flex_cost": flex_cost,
36
- "total_monthly_cost": total_monthly_cost
 
37
  }
38
 
39
  def generate_cost_projection(
@@ -42,28 +61,31 @@ def generate_cost_projection(
42
  execution_time,
43
  active_cost,
44
  flex_cost,
45
- active_percentage,
46
- cold_start
 
47
  ):
48
  # Generate data for different request volumes
49
  request_volumes = np.linspace(min_requests, max_requests, 20)
50
  results = []
51
 
52
  for req_vol in request_volumes:
53
- result = calculate_runpod_cost(
54
  req_vol,
55
  execution_time,
56
  active_cost,
57
  flex_cost,
58
  cold_start,
59
- active_percentage/100
 
60
  )
61
  results.append({
62
  'requests_per_hour': req_vol,
63
  'monthly_requests': result['monthly_requests'],
64
  'active_cost': result['active_cost'],
65
  'flex_cost': result['flex_cost'],
66
- 'total_cost': result['total_monthly_cost']
 
67
  })
68
 
69
  df = pd.DataFrame(results)
@@ -103,16 +125,18 @@ def calculate_specific_cost(
103
  execution_time,
104
  active_cost,
105
  flex_cost,
106
- active_percentage,
107
- cold_start
 
108
  ):
109
- result = calculate_runpod_cost(
110
  requests,
111
  execution_time,
112
  active_cost,
113
  flex_cost,
114
  cold_start,
115
- active_percentage/100
 
116
  )
117
 
118
  # Format the output HTML for the table
@@ -126,6 +150,14 @@ def calculate_specific_cost(
126
  <td style="padding: 8px; border: 1px solid #ddd;">Monthly Requests</td>
127
  <td style="padding: 8px; text-align: right; border: 1px solid #ddd;">{result['monthly_requests']:,.0f}</td>
128
  </tr>
 
 
 
 
 
 
 
 
129
  <tr>
130
  <td style="padding: 8px; border: 1px solid #ddd;">Active Worker Cost</td>
131
  <td style="padding: 8px; text-align: right; border: 1px solid #ddd;">${result['active_cost']:,.2f}</td>
@@ -138,11 +170,16 @@ def calculate_specific_cost(
138
  <td style="padding: 8px; border: 1px solid #ddd;">Total Monthly Cost</td>
139
  <td style="padding: 8px; text-align: right; border: 1px solid #ddd;">${result['total_monthly_cost']:,.2f}</td>
140
  </tr>
 
 
 
 
141
  </table>
142
  """
143
 
144
  return html
145
 
 
146
  theme = gr.themes.Default(
147
  primary_hue=gr.themes.colors.red,
148
  secondary_hue=gr.themes.colors.red,
@@ -161,8 +198,9 @@ with gr.Blocks(title="RunPod Serverless Cost Estimator", theme=theme) as demo:
161
  execution_time = gr.Slider(minimum=1, maximum=120, value=30, step=1, label="Execution Time per Request (seconds)")
162
  active_cost = gr.Number(value=0.00019, label="Active Worker Cost ($/second)", precision=5)
163
  flex_cost = gr.Number(value=0.00031, label="Flex Worker Cost ($/second)", precision=5)
164
- active_percentage = gr.Slider(minimum=0, maximum=100, value=50, step=1, label="% Requests on Active Workers")
165
- cold_start = gr.Slider(minimum=0, maximum=60, value=30, step=1, label="Cold Start Penalty (seconds)")
 
166
 
167
  plot_button = gr.Button("Generate Cost Projection")
168
 
@@ -181,13 +219,13 @@ with gr.Blocks(title="RunPod Serverless Cost Estimator", theme=theme) as demo:
181
 
182
  plot_button.click(
183
  generate_cost_projection,
184
- inputs=[min_requests, max_requests, execution_time, active_cost, flex_cost, active_percentage, cold_start],
185
  outputs=plot_output
186
  )
187
 
188
  calc_button.click(
189
  calculate_specific_cost,
190
- inputs=[specific_requests, execution_time, active_cost, flex_cost, active_percentage, cold_start],
191
  outputs=cost_table
192
  )
193
 
 
3
  import pandas as pd
4
  import numpy as np
5
 
6
+ def calculate_runpod_cost_revised(
7
  requests_per_hour,
8
  execution_time_per_request,
9
  active_cost_per_second,
10
  flex_cost_per_second,
11
+ cold_start_penalty,
12
+ num_active_workers,
13
+ concurrent_batch_size=1 # How many requests can be processed simultaneously by one worker
14
  ):
15
+ # Monthly hours and requests
16
+ monthly_hours = 24 * 30
17
+ seconds_per_hour = 3600
18
+ monthly_requests = requests_per_hour * monthly_hours
19
 
20
+ # Calculate active worker capacity (requests per hour)
21
+ # Each worker can process (concurrent_batch_size) requests at a time
22
+ active_capacity_per_hour = (seconds_per_hour / execution_time_per_request) * num_active_workers * concurrent_batch_size
23
 
24
+ # Total requests handled by active workers over the month
25
+ active_requests_handled = min(monthly_requests, active_capacity_per_hour * monthly_hours)
26
 
27
+ # Remaining requests go to flex workers
28
+ flex_requests = max(0, monthly_requests - active_requests_handled)
29
+
30
+ # Active worker cost (constant regardless of actual usage)
31
+ active_cost = num_active_workers * active_cost_per_second * seconds_per_hour * monthly_hours
32
+
33
+ # For flex workers, we calculate cold starts based on request arrival pattern
34
+ # This is simplified - in reality depends on actual traffic patterns
35
+ avg_requests_per_cold_start = concurrent_batch_size * 2 # Estimate that batches arrive close enough to reuse some workers
36
+ cold_starts = flex_requests / avg_requests_per_cold_start if flex_requests > 0 else 0
37
+
38
+ # Flex worker cost (only pay for processing time + cold starts)
39
+ flex_processing_cost = flex_requests * execution_time_per_request * flex_cost_per_second
40
+ flex_cold_start_cost = cold_starts * cold_start_penalty * flex_cost_per_second
41
+ flex_cost = flex_processing_cost + flex_cold_start_cost
42
+
43
+ # Active worker utilization
44
+ active_utilization = (active_requests_handled / (active_capacity_per_hour * monthly_hours) * 100) if num_active_workers > 0 else 0
45
 
 
46
  total_monthly_cost = active_cost + flex_cost
47
 
48
  return {
49
  "monthly_requests": monthly_requests,
50
+ "active_requests": active_requests_handled,
51
  "flex_requests": flex_requests,
52
  "active_cost": active_cost,
53
  "flex_cost": flex_cost,
54
+ "total_monthly_cost": total_monthly_cost,
55
+ "active_utilization": active_utilization
56
  }
57
 
58
  def generate_cost_projection(
 
61
  execution_time,
62
  active_cost,
63
  flex_cost,
64
+ num_active_workers,
65
+ cold_start,
66
+ concurrent_batch_size
67
  ):
68
  # Generate data for different request volumes
69
  request_volumes = np.linspace(min_requests, max_requests, 20)
70
  results = []
71
 
72
  for req_vol in request_volumes:
73
+ result = calculate_runpod_cost_revised(
74
  req_vol,
75
  execution_time,
76
  active_cost,
77
  flex_cost,
78
  cold_start,
79
+ num_active_workers,
80
+ concurrent_batch_size
81
  )
82
  results.append({
83
  'requests_per_hour': req_vol,
84
  'monthly_requests': result['monthly_requests'],
85
  'active_cost': result['active_cost'],
86
  'flex_cost': result['flex_cost'],
87
+ 'total_cost': result['total_monthly_cost'],
88
+ 'active_utilization': result['active_utilization']
89
  })
90
 
91
  df = pd.DataFrame(results)
 
125
  execution_time,
126
  active_cost,
127
  flex_cost,
128
+ num_active_workers,
129
+ cold_start,
130
+ concurrent_batch_size
131
  ):
132
+ result = calculate_runpod_cost_revised(
133
  requests,
134
  execution_time,
135
  active_cost,
136
  flex_cost,
137
  cold_start,
138
+ num_active_workers,
139
+ concurrent_batch_size
140
  )
141
 
142
  # Format the output HTML for the table
 
150
  <td style="padding: 8px; border: 1px solid #ddd;">Monthly Requests</td>
151
  <td style="padding: 8px; text-align: right; border: 1px solid #ddd;">{result['monthly_requests']:,.0f}</td>
152
  </tr>
153
+ <tr>
154
+ <td style="padding: 8px; border: 1px solid #ddd;">Requests Handled by Active Workers</td>
155
+ <td style="padding: 8px; text-align: right; border: 1px solid #ddd;">{result['active_requests']:,.0f}</td>
156
+ </tr>
157
+ <tr>
158
+ <td style="padding: 8px; border: 1px solid #ddd;">Requests Handled by Flex Workers</td>
159
+ <td style="padding: 8px; text-align: right; border: 1px solid #ddd;">{result['flex_requests']:,.0f}</td>
160
+ </tr>
161
  <tr>
162
  <td style="padding: 8px; border: 1px solid #ddd;">Active Worker Cost</td>
163
  <td style="padding: 8px; text-align: right; border: 1px solid #ddd;">${result['active_cost']:,.2f}</td>
 
170
  <td style="padding: 8px; border: 1px solid #ddd;">Total Monthly Cost</td>
171
  <td style="padding: 8px; text-align: right; border: 1px solid #ddd;">${result['total_monthly_cost']:,.2f}</td>
172
  </tr>
173
+ <tr>
174
+ <td style="padding: 8px; border: 1px solid #ddd;">Active Worker Utilization</td>
175
+ <td style="padding: 8px; text-align: right; border: 1px solid #ddd;">{result['active_utilization']:.1f}%</td>
176
+ </tr>
177
  </table>
178
  """
179
 
180
  return html
181
 
182
+ # Create theme
183
  theme = gr.themes.Default(
184
  primary_hue=gr.themes.colors.red,
185
  secondary_hue=gr.themes.colors.red,
 
198
  execution_time = gr.Slider(minimum=1, maximum=120, value=30, step=1, label="Execution Time per Request (seconds)")
199
  active_cost = gr.Number(value=0.00019, label="Active Worker Cost ($/second)", precision=5)
200
  flex_cost = gr.Number(value=0.00031, label="Flex Worker Cost ($/second)", precision=5)
201
+ num_active_workers = gr.Slider(minimum=0, maximum=600, value=30, step=10, label="Number of Active Workers")
202
+ cold_start = gr.Slider(minimum=0, maximum=60, value=1, step=1, label="Cold Start Penalty (seconds)")
203
+ concurrent_batch_size = gr.Slider(minimum=1, maximum=10, value=2, step=1, label="Concurrent Requests per Worker")
204
 
205
  plot_button = gr.Button("Generate Cost Projection")
206
 
 
219
 
220
  plot_button.click(
221
  generate_cost_projection,
222
+ inputs=[min_requests, max_requests, execution_time, active_cost, flex_cost, num_active_workers, cold_start, concurrent_batch_size],
223
  outputs=plot_output
224
  )
225
 
226
  calc_button.click(
227
  calculate_specific_cost,
228
+ inputs=[specific_requests, execution_time, active_cost, flex_cost, num_active_workers, cold_start, concurrent_batch_size],
229
  outputs=cost_table
230
  )
231