13
13
import os
14
14
import csv
15
15
import io
16
+ import re
16
17
17
18
18
19
def isUMFAvailable ():
@@ -40,96 +41,44 @@ def benchmarks(self) -> list[Benchmark]:
40
41
GBenchUmfProxy (self ),
41
42
GBenchJemalloc (self ),
42
43
GBenchTbbProxy (self ),
44
+ GBenchMemoryOverhead (self ),
43
45
]
44
46
45
47
return benches
46
48
47
49
48
- class ComputeUMFBenchmark (Benchmark ):
49
- def __init__ (self , bench , name ):
50
+ class GBench (Benchmark ):
51
+ def __init__ (self , bench ):
50
52
super ().__init__ (bench .directory , bench )
51
53
52
54
self .bench = bench
53
- self .bench_name = name
55
+ self .bench_name = "umf-benchmark"
54
56
self .oneapi = get_oneapi ()
57
+ self .umf_lib = options .umf + "lib"
55
58
56
- self .col_name = None
57
- self .col_iterations = None
58
- self .col_real_time = None
59
- self .col_cpu_time = None
60
- self .col_time_unit = None
61
-
62
- self .col_statistics_time = None
63
-
64
- def bin_args (self ) -> list [str ]:
65
- return []
66
-
67
- def extra_env_vars (self ) -> dict :
68
- return {}
69
-
70
- def setup (self ):
71
- if not isUMFAvailable ():
72
- print ("UMF prefix path not provided" )
73
- return
74
-
75
- self .benchmark_bin = os .path .join (options .umf , "benchmark" , self .bench_name )
76
-
77
- def get_tags (self ):
78
- return ["UMF" , "allocation" , "latency" , "micro" ]
79
-
80
- def run (self , env_vars ) -> list [Result ]:
81
- command = [
82
- f"{ self .benchmark_bin } " ,
83
- ]
84
-
85
- command += self .bin_args ()
86
- env_vars .update (self .extra_env_vars ())
87
-
88
- result = self .run_bench (
89
- command , env_vars , add_sycl = False , ld_library = [self .oneapi .tbb_lib ()]
90
- )
91
- parsed = self .parse_output (result )
92
- results = []
93
- for r in parsed :
94
- (config , pool , mean ) = r
95
- label = f"{ config } { pool } "
96
- results .append (
97
- Result (
98
- label = label ,
99
- value = mean ,
100
- command = command ,
101
- env = env_vars ,
102
- stdout = result ,
103
- unit = "ns" ,
104
- explicit_group = config ,
105
- )
106
- )
107
- return results
108
-
109
- # Implementation with self.col_* indices could lead to the division by None
110
- def get_mean (self , datarow ):
111
- raise NotImplementedError ()
112
-
113
- def teardown (self ):
114
- return
115
-
116
-
117
- class GBench (ComputeUMFBenchmark ):
118
- def __init__ (self , bench ):
119
- super ().__init__ (bench , "umf-benchmark" )
59
+ self .num_cols_with_memory = 13
120
60
121
61
self .col_name = 0
122
62
self .col_iterations = 1
123
63
self .col_real_time = 2
124
64
self .col_cpu_time = 3
125
65
self .col_time_unit = 4
66
+ self .col_memory_overhead = 11
126
67
127
68
self .idx_pool = 0
128
69
self .idx_config = 1
129
70
self .name_separator = "/"
130
71
131
72
self .col_statistics_time = self .col_real_time
132
73
74
+ self .is_preloaded = False
75
+ self .is_memory_overhead_checked = False
76
+
77
+ self .lib_to_be_replaced = None
78
+
79
+ def is_memory_statistics_included (self , data_row ):
80
+ return len (data_row ) == self .num_cols_with_memory
81
+
133
82
def name (self ):
134
83
return self .bench_name
135
84
@@ -160,44 +109,70 @@ def get_pool_and_config(self, full_name):
160
109
def get_mean (self , datarow ):
161
110
return float (datarow [self .col_statistics_time ])
162
111
163
- def parse_output (self , output ):
164
- csv_file = io .StringIO (output )
165
- reader = csv .reader (csv_file )
112
+ def get_memory_overhead (self , datarow ):
113
+ return float (datarow [self .col_memory_overhead ])
166
114
167
- data_row = next (reader , None )
168
- if data_row is None :
169
- raise ValueError ("Benchmark output does not contain data." )
115
+ def extra_env_vars (self ) -> dict :
116
+ return {}
170
117
171
- results = []
172
- for row in reader :
173
- try :
174
- full_name = row [self .col_name ]
175
- pool , config = self .get_pool_and_config (full_name )
176
- mean = self .get_mean (row )
177
- results .append ((config , pool , mean ))
178
- except KeyError as e :
179
- raise ValueError (f"Error parsing output: { e } " )
118
+ def setup (self ):
119
+ if not isUMFAvailable ():
120
+ print ("UMF prefix path not provided" )
121
+ return
180
122
181
- return results
123
+ self . benchmark_bin = os . path . join ( options . umf , "benchmark" , self . bench_name )
182
124
125
+ def get_names_of_benchmarks_to_be_run (self , command , env_vars ):
126
+ list_all_command = command + ["--benchmark_list_tests" ]
183
127
184
- class GBenchPreloaded (GBench ):
185
- def __init__ (self , bench , lib_to_be_replaced , replacing_lib ):
186
- super ().__init__ (bench )
128
+ if self .is_preloaded :
129
+ list_all_command += ["--benchmark_filter=" + self .lib_to_be_replaced ]
187
130
188
- self .lib_to_be_replaced = lib_to_be_replaced
189
- self .replacing_lib = replacing_lib
131
+ all_names = self .run_bench (
132
+ list_all_command , env_vars , add_sycl = False , ld_library = [self .umf_lib ]
133
+ ).splitlines ()
190
134
191
- def bin_args (self ):
192
- full_args = super ().bin_args ()
193
- full_args .append (f"--benchmark_filter={ self .lib_to_be_replaced } " )
135
+ if self .is_memory_overhead_checked :
136
+ all_names = [
137
+ name for name in all_names if re .search ("^glibc" , name ) is None
138
+ ]
194
139
195
- return full_args
140
+ return all_names
196
141
197
- def get_preloaded_name (self , pool_name ) -> str :
198
- new_pool_name = pool_name . replace ( self .lib_to_be_replaced , self . replacing_lib )
142
+ def run (self , env_vars ) -> list [ Result ] :
143
+ command = [ f" { self .benchmark_bin } " ]
199
144
200
- return new_pool_name
145
+ all_names = self .get_names_of_benchmarks_to_be_run (command , env_vars )
146
+
147
+ command += self .bin_args ()
148
+ env_vars .update (self .extra_env_vars ())
149
+
150
+ results = []
151
+
152
+ for name in all_names :
153
+ specific_benchmark = command + ["--benchmark_filter=^" + name + "$" ]
154
+
155
+ result = self .run_bench (
156
+ specific_benchmark , env_vars , add_sycl = False , ld_library = [self .umf_lib ]
157
+ )
158
+
159
+ parsed = self .parse_output (result )
160
+ for r in parsed :
161
+ (config , pool , mean ) = r
162
+ label = f"{ config } { pool } "
163
+ results .append (
164
+ Result (
165
+ label = label ,
166
+ value = mean ,
167
+ command = command ,
168
+ env = env_vars ,
169
+ stdout = result ,
170
+ unit = self .unit (),
171
+ explicit_group = config ,
172
+ )
173
+ )
174
+
175
+ return results
201
176
202
177
def parse_output (self , output ):
203
178
csv_file = io .StringIO (output )
@@ -208,20 +183,56 @@ def parse_output(self, output):
208
183
raise ValueError ("Benchmark output does not contain data." )
209
184
210
185
results = []
186
+
211
187
for row in reader :
212
188
try :
213
189
full_name = row [self .col_name ]
214
190
pool , config = self .get_pool_and_config (full_name )
215
- mean = self .get_mean (row )
216
- updated_pool = self .get_preloaded_name (pool )
217
- updated_config = self .get_preloaded_name (config )
191
+ statistics = None
192
+ is_row_matched_to_statistics_type = False
193
+
194
+ if not self .is_memory_overhead_checked :
195
+ statistics = self .get_mean (row )
196
+
197
+ is_row_matched_to_statistics_type = True
198
+
199
+ # At this moment, preloaded benchmarks
200
+ # do not support memory statitics
201
+ if self .is_preloaded :
202
+ pool = self .get_preloaded_pool_name (pool )
203
+
204
+ elif self .is_memory_statistics_included (row ):
205
+ statistics = self .get_memory_overhead (row )
206
+ config = "FRAGMENTATION_" + config
207
+
208
+ is_row_matched_to_statistics_type = True
209
+
210
+ if is_row_matched_to_statistics_type :
211
+ results .append ((config , pool , statistics ))
218
212
219
- results .append ((updated_config , updated_pool , mean ))
220
213
except KeyError as e :
221
214
raise ValueError (f"Error parsing output: { e } " )
222
215
223
216
return results
224
217
218
+ def teardown (self ):
219
+ return
220
+
221
+
222
+ class GBenchPreloaded (GBench ):
223
+ def __init__ (self , bench , lib_to_be_replaced , replacing_lib ):
224
+ super ().__init__ (bench )
225
+
226
+ self .is_preloaded = True
227
+
228
+ self .lib_to_be_replaced = lib_to_be_replaced
229
+ self .replacing_lib = replacing_lib
230
+
231
+ def get_preloaded_pool_name (self , pool_name ) -> str :
232
+ new_pool_name = pool_name .replace (self .lib_to_be_replaced , self .replacing_lib )
233
+
234
+ return new_pool_name
235
+
225
236
226
237
class GBenchGlibc (GBenchPreloaded ):
227
238
def __init__ (self , bench , replacing_lib ):
@@ -251,3 +262,13 @@ def __init__(self, bench):
251
262
252
263
def extra_env_vars (self ) -> dict :
253
264
return {"LD_PRELOAD" : "libtbbmalloc_proxy.so" }
265
+
266
+
267
+ class GBenchMemoryOverhead (GBench ):
268
+ def __init__ (self , bench ):
269
+ super ().__init__ (bench )
270
+
271
+ self .is_memory_overhead_checked = True
272
+
273
+ def unit (self ):
274
+ return "%"
0 commit comments