7
7
from enum import Enum
8
8
from operator import itemgetter
9
9
from pathlib import Path
10
- from pydantic import BaseModel , Field , NonNegativeFloat , NonNegativeInt , PositiveInt , StrictBool , ValidationError , confloat , model_validator
10
+ from pydantic import BaseModel , Field , NonNegativeFloat , NonNegativeInt , PositiveInt , StrictBool , ValidationError , model_validator
11
11
from typing import Any , Callable , Dict , List , Optional
12
12
13
13
from scalene .scalene_leak_analysis import ScaleneLeakAnalysis
14
14
from scalene .scalene_statistics import Filename , LineNumber , ScaleneStatistics
15
15
from scalene .scalene_analysis import ScaleneAnalysis
16
16
17
- import numpy as np
18
17
19
18
class GPUDevice (str , Enum ):
20
19
nvidia = "GPU"
@@ -23,26 +22,26 @@ class GPUDevice(str, Enum):
23
22
24
23
class FunctionDetail (BaseModel ):
25
24
line : str
26
- lineno : PositiveInt
25
+ lineno : LineNumber
27
26
memory_samples : List [List [Any ]]
28
27
n_avg_mb : NonNegativeFloat
29
28
n_copy_mb_s : NonNegativeFloat
30
- n_core_utilization : float = Field (confloat ( ge = 0 , le = 1 ) )
31
- n_cpu_percent_c : float = Field (confloat ( ge = 0 , le = 100 ) )
32
- n_cpu_percent_python : float = Field (confloat ( ge = 0 , le = 100 ) )
29
+ n_core_utilization : float = Field (..., ge = 0 , le = 1 )
30
+ n_cpu_percent_c : float = Field (..., ge = 0 , le = 100 )
31
+ n_cpu_percent_python : float = Field (..., ge = 0 , le = 100 )
33
32
n_gpu_avg_memory_mb : NonNegativeFloat
34
33
n_gpu_peak_memory_mb : NonNegativeFloat
35
- n_gpu_percent : float = Field (confloat ( ge = 0 , le = 100 ) )
34
+ n_gpu_percent : float = Field (..., ge = 0 , le = 100 )
36
35
n_growth_mb : NonNegativeFloat
37
36
n_peak_mb : NonNegativeFloat
38
37
n_malloc_mb : NonNegativeFloat
39
38
n_mallocs : NonNegativeInt
40
- n_python_fraction : float = Field (confloat ( ge = 0 , le = 1 ) )
41
- n_sys_percent : float = Field (confloat ( ge = 0 , le = 100 ) )
42
- n_usage_fraction : float = Field (confloat ( ge = 0 , le = 1 ) )
39
+ n_python_fraction : float = Field (..., ge = 0 , le = 1 )
40
+ n_sys_percent : float = Field (..., ge = 0 , le = 100 )
41
+ n_usage_fraction : float = Field (..., ge = 0 , le = 1 )
43
42
44
43
@model_validator (mode = "after" )
45
- def check_cpu_percentages (cls , values ) :
44
+ def check_cpu_percentages (cls , values : Any ) -> Any :
46
45
total_cpu_usage = math .floor (
47
46
values .n_cpu_percent_c
48
47
+ values .n_cpu_percent_python
@@ -56,15 +55,15 @@ def check_cpu_percentages(cls, values):
56
55
57
56
58
57
@model_validator (mode = "after" )
59
- def check_gpu_memory (cls , values ) :
58
+ def check_gpu_memory (cls , values : Any ) -> Any :
60
59
if values .n_gpu_avg_memory_mb > values .n_gpu_peak_memory_mb :
61
60
raise ValueError (
62
61
"n_gpu_avg_memory_mb must be less than or equal to n_gpu_peak_memory_mb"
63
62
)
64
63
return values
65
64
66
65
@model_validator (mode = "after" )
67
- def check_cpu_memory (cls , values ) :
66
+ def check_cpu_memory (cls , values : Any ) -> Any :
68
67
if values .n_avg_mb > values .n_peak_mb :
69
68
raise ValueError (
70
69
"n_avg_mb must be less than or equal to n_peak_mb"
@@ -159,79 +158,18 @@ def __init__(self) -> None:
159
158
self .gpu = False
160
159
self .gpu_device = ""
161
160
162
- def rdp (self , points , epsilon ):
163
- """
164
- Ramer-Douglas-Peucker algorithm implementation using NumPy
165
- """
166
-
167
- def perpendicular_distance (point , start , end ):
168
- if np .all (start == end ):
169
- return np .linalg .norm (point - start )
170
- return np .abs (
171
- np .cross (end - start , start - point )
172
- / np .linalg .norm (end - start )
173
- )
174
-
175
- def recursive_rdp (points , start : int , end : int , epsilon : float ):
176
- dmax = 0.0
177
- index = start
178
- for i in range (start + 1 , end ):
179
- d = perpendicular_distance (
180
- points [i ], points [start ], points [end ]
181
- )
182
- if d > dmax :
183
- index = i
184
- dmax = d
185
- if dmax > epsilon :
186
- results1 = recursive_rdp (points , start , index , epsilon )
187
- results2 = recursive_rdp (points , index , end , epsilon )
188
- return results1 [:- 1 ] + results2
189
- else :
190
- return [points [start ], points [end ]]
191
-
192
- points = np .array (points )
193
- start = 0
194
- end = len (points ) - 1
195
- return np .array (recursive_rdp (points , start , end , epsilon ))
196
-
197
161
def compress_samples (
198
162
self , samples : List [Any ], max_footprint : float
199
163
) -> Any :
200
- # Try to reduce the number of samples with the
201
- # Ramer-Douglas-Peucker algorithm, which attempts to
202
- # preserve the shape of the graph. If that fails to bring
203
- # the number of samples below our maximum, randomly
204
- # downsample (epsilon calculation from
205
- # https://stackoverflow.com/questions/57052434/can-i-guess-the-appropriate-epsilon-for-rdp-ramer-douglas-peucker)
206
164
if len (samples ) <= self .max_sparkline_samples :
207
165
return samples
208
166
209
- if True :
210
- # FIXME: bypassing RDP for now
211
- # return samples[:self.max_sparkline_samples]
212
-
213
- new_samples = sorted (
214
- random .sample (
215
- list (map (tuple , samples )), self .max_sparkline_samples
216
- )
167
+ new_samples = sorted (
168
+ random .sample (
169
+ list (map (tuple , samples )), self .max_sparkline_samples
217
170
)
218
- return new_samples
219
-
220
- else :
221
- epsilon = (len (samples ) / (3 * self .max_sparkline_samples )) * 2
222
-
223
- # Use NumPy for RDP algorithm
224
- new_samples = self .rdp (np .array (samples ), epsilon )
225
-
226
- if len (new_samples ) > self .max_sparkline_samples :
227
- new_samples = sorted (
228
- random .sample (
229
- list (map (tuple , new_samples )),
230
- self .max_sparkline_samples ,
231
- )
232
- )
233
-
234
- return new_samples
171
+ )
172
+ return new_samples
235
173
236
174
# Profile output methods
237
175
def output_profile_line (
@@ -355,24 +293,24 @@ def output_profile_line(
355
293
)
356
294
357
295
payload = {
358
- "lineno" : line_no ,
359
296
"line" : line ,
297
+ "lineno" : line_no ,
298
+ "memory_samples" : stats .per_line_footprint_samples [fname ][line_no ],
299
+ "n_avg_mb" : n_avg_mb ,
300
+ "n_copy_mb_s" : n_copy_mb_s ,
360
301
"n_core_utilization" : mean_core_util ,
361
302
"n_cpu_percent_c" : n_cpu_percent_c ,
362
303
"n_cpu_percent_python" : n_cpu_percent_python ,
363
- "n_sys_percent" : n_sys_percent ,
364
- "n_gpu_percent" : n_gpu_percent ,
365
304
"n_gpu_avg_memory_mb" : n_gpu_mem_samples .mean (),
366
305
"n_gpu_peak_memory_mb" : n_gpu_mem_samples .peak (),
367
- "n_peak_mb " : n_peak_mb ,
306
+ "n_gpu_percent " : n_gpu_percent ,
368
307
"n_growth_mb" : n_peak_mb , # For backwards compatibility
369
- "n_avg_mb" : n_avg_mb ,
370
- "n_mallocs" : n_mallocs ,
308
+ "n_peak_mb" : n_peak_mb ,
371
309
"n_malloc_mb" : n_malloc_mb ,
372
- "n_usage_fraction " : n_usage_fraction ,
310
+ "n_mallocs " : n_mallocs ,
373
311
"n_python_fraction" : n_python_fraction ,
374
- "n_copy_mb_s " : n_copy_mb_s ,
375
- "memory_samples " : stats . per_line_footprint_samples [ fname ][ line_no ] ,
312
+ "n_sys_percent " : n_sys_percent ,
313
+ "n_usage_fraction " : n_usage_fraction ,
376
314
}
377
315
try :
378
316
FunctionDetail (** payload )
0 commit comments