-
Notifications
You must be signed in to change notification settings - Fork 1
Expand file tree
/
Copy pathbenchmark_priority_queue.mpc
More file actions
313 lines (272 loc) · 9.84 KB
/
benchmark_priority_queue.mpc
File metadata and controls
313 lines (272 loc) · 9.84 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
from Compiler import library as lib, oram, path_oram
from Compiler.dijkstra import HeapQ
from Compiler.path_oblivious_heap import (
POHToHeapQAdapter,
POHVariant,
UniquePOHToHeapQAdapter,
path_oblivious_sort,
)
from Compiler.types import Array, sint
from Compiler.util import log2
DEBUG = True
from Compiler import path_oblivious_heap
path_oblivious_heap.DEBUG = False
def noop(*args, **kwargs):
pass
# Only print if DEBUG is enabled
dprint = lib.print_ln if DEBUG else noop
# Benchmark types
INSERT = True
EXTRACT = True
SORTING = False
INSERT = INSERT or EXTRACT # Always insert if we are going to extract
# Benchmark parameters
## General
KEY_SIZE = lambda n: 32
VALUE_SIZE = lambda n: log2(n)
N_THREADS = 1
N_PARALLEL = 1
## Insert / ExtractMin
RANGE = [2**i for i in range(1, 18)]
# Important: there must be space to insert this amount of entries in the queue
OPERATIONS_PER_STEP = 10
TIME_INIT = True
TREE_HEAP = False
TREE_PATH_HEAP = False
LINEAR_HEAP = False
OPTIMAL_TREE_HEAP = False
OPTIMAL_PATH_HEAP = False
POH_PATH = True
POH_PATH_CONSTANT_STASH = True
UNIQUE_POH_PATH_LINEAR = False
UNIQUE_POH_PATH_PATH = False
UNIQUE_POH_PATH_CONSTANT_STASH_LINEAR = False
UNIQUE_POH_PATH_CONSTANT_STASH_PATH = False
## Sorting
LENGTHS = [2**i for i in range(1, 10)]
SORTING_BITS = 32
RADIX_SORT = True
POS = True
POS_CONSTANT_STASH = True
# Set module variables based on parameters
oram.n_threads = N_THREADS
oram.n_parallel = N_PARALLEL
oram.n_threads_for_tree = N_THREADS
# Timing with consecutive ids
timer_offset = 1000 # Hopefully run timers in an unused range
def start_fancy_timer(id: int | None = None) -> int:
global timer_offset
_id = id if id is not None else timer_offset
lib.start_timer(_id)
if id is None:
timer_offset += 1
return _id
def stop_fancy_timer(id):
lib.stop_timer(id)
# BENCHMARK
if INSERT:
def operation_round(i, id, q, apply_op, capacity, tag=""):
dprint(f"\n[{tag}] Update %s for capacity {capacity}", i.reveal())
start_fancy_timer(id)
apply_op(q, i)
stop_fancy_timer(id)
def benchmark_operations(q_init, capacity, *args, tag="", **kwargs):
global timer_offset
apply_insert = lambda q, i: q.update(0, i)
apply_extract = lambda q, _: q.pop()
init_id = timer_offset
insert_id = init_id + 1
extract_id = insert_id + 1
dprint(
f"\n[{tag}] Running {OPERATIONS_PER_STEP} update{'s' if OPERATIONS_PER_STEP > 1 else ''} for capacity {capacity}"
)
@lib.for_range(OPERATIONS_PER_STEP)
def _(i):
dprint(f"\n[{tag}] Initializing empty structure with capacity {capacity}")
if TIME_INIT:
start_fancy_timer(init_id)
q = q_init(capacity, *args, **kwargs)
if TIME_INIT:
stop_fancy_timer(init_id)
if INSERT:
operation_round(
i, insert_id, q, apply_insert, capacity, tag=tag + " insert"
)
if EXTRACT:
operation_round(
i,
extract_id,
q,
apply_extract,
capacity,
tag=tag + " extract_min",
)
timer_offset += 3
dprint(f"\n\nBENCHMARKING INSERT {'AND EXTRACT ' if EXTRACT else ''}TIME")
for capacity in RANGE:
entry_size = (KEY_SIZE(capacity), VALUE_SIZE(capacity))
dprint(f"\nCAPACITY {capacity}")
if TREE_HEAP:
# Benchmark binary heap built on ORAM (Tree ORAM variant)
benchmark_operations(
HeapQ,
capacity,
oram_type=oram.RecursiveORAM,
entry_size=entry_size,
tag="ORAM Heap (Tree)",
)
if TREE_PATH_HEAP:
# Benchmark binary heap built on ORAM (Path ORAM variant)
benchmark_operations(
HeapQ,
capacity,
oram_type=path_oram.RecursivePathORAM,
entry_size=entry_size,
tag="ORAM Heap (Path)",
)
if LINEAR_HEAP:
# Benchmark binary heap built on ORAM (Linear ORAM variant)
benchmark_operations(
HeapQ,
capacity,
oram_type=oram.LinearORAM,
entry_size=entry_size,
tag="ORAM Heap (Linear)",
)
if OPTIMAL_TREE_HEAP:
# Benchmark binary heap built on ORAM (OptimalORAM variant)
benchmark_operations(
HeapQ,
capacity,
oram_type=oram.OptimalORAM,
entry_size=entry_size,
tag="ORAM Heap (Optimal Tree)",
)
if OPTIMAL_PATH_HEAP:
# Benchmark binary heap built on ORAM (OptimalORAM Path variant)
benchmark_operations(
HeapQ,
capacity,
oram_type=path_oram.OptimalORAM,
entry_size=entry_size,
tag="ORAM Heap (Optimal Path)",
)
if POH_PATH:
# Benchmark Path Oblivious Heap (Path variant)
benchmark_operations(
POHToHeapQAdapter,
capacity,
bucket_size=2,
stash_size=log2(capacity) ** 2,
variant=POHVariant.PATH,
entry_size=entry_size,
tag="POH (Path (superlogarithmic stash size))",
)
if POH_PATH_CONSTANT_STASH:
# Benchmark Path Oblivious Heap (Path variant with constant stash size)
benchmark_operations(
POHToHeapQAdapter,
capacity,
bucket_size=2,
stash_size=20, # based on empirical analysis by Keller and Scholl
variant=POHVariant.PATH,
entry_size=entry_size,
tag="POH (Path (constant stash size))",
)
if UNIQUE_POH_PATH_LINEAR:
# Benchmark Unique Path Oblivious Heap (Path variant with constant stash size and linear ORAM)
benchmark_operations(
UniquePOHToHeapQAdapter,
capacity,
bucket_size=2,
stash_size=log2(capacity) ** 2,
variant=POHVariant.PATH,
oram_type=oram.LinearORAM,
entry_size=entry_size,
tag="Unique POH (Path (superlogarithmic stash size)) (Linear ORAM)",
)
if UNIQUE_POH_PATH_PATH:
# Benchmark Unique Path Oblivious Heap (Path variant with constant stash size and linear ORAM)
benchmark_operations(
UniquePOHToHeapQAdapter,
capacity,
bucket_size=2,
stash_size=log2(capacity) ** 2,
variant=POHVariant.PATH,
oram_type=path_oram.RecursivePathORAM,
entry_size=entry_size,
tag="Unique POH (Path (superlogarithmic stash size)) (Path ORAM)",
)
if UNIQUE_POH_PATH_CONSTANT_STASH_LINEAR:
benchmark_operations(
UniquePOHToHeapQAdapter,
capacity,
bucket_size=2,
stash_size=20,
variant=POHVariant.PATH,
oram_type=oram.LinearORAM,
entry_size=entry_size,
tag="Unique POH (Path (constant stash size)) (Linear ORAM)",
)
if UNIQUE_POH_PATH_CONSTANT_STASH_PATH:
benchmark_operations(
UniquePOHToHeapQAdapter,
capacity,
bucket_size=2,
stash_size=20,
variant=POHVariant.PATH,
oram_type=path_oram.RecursivePathORAM,
entry_size=entry_size,
tag="Unique POH (Path (constant stash size)) (Path ORAM)",
)
if SORTING:
dprint("\n\nBENCHMARKING SORTING TIME")
for n in LENGTHS:
dprint(f"\nLENGTH {n}")
a = Array(n, sint)
@lib.for_range(n)
def _(i):
a[i] = sint.get_random_int(SORTING_BITS)
if RADIX_SORT:
a_ = Array(n, sint).assign(a)
lib.print_ln(
"\n[Sorting (Radix)] Unsorted array of length %s: %s", n, a_.reveal()
)
lib.print_ln("[Sorting (Radix)] Sorting array...")
id = start_fancy_timer()
a_.sort()
stop_fancy_timer(id)
lib.print_ln("[Sorting (Radix)] Sorted array: %s", a_.reveal())
if POS:
a_ = Array(n, sint).assign(a)
lib.print_ln(
"\n[Sorting (POH) superlogarithmic stash size] Unsorted array of length %s: %s",
n,
a_.reveal(),
)
lib.print_ln("[Sorting (POH) superlogarithmic stash size] Sorting array...")
id = start_fancy_timer()
path_oblivious_sort(
a_, a_, SORTING_BITS, stash_size=log2(n) ** 2, variant=POHVariant.PATH
)
stop_fancy_timer(id)
lib.print_ln(
"[Sorting (POH) superlogarithmic stash size] Sorted array: %s",
a_.reveal(),
)
if POS_CONSTANT_STASH:
a_ = Array(n, sint).assign(a)
lib.print_ln(
"\n[Sorting (POH) constant stash size] Unsorted array of length %s: %s",
n,
a_.reveal(),
)
lib.print_ln("[Sorting (POH) constant stash size] Sorting array...")
id = start_fancy_timer()
path_oblivious_sort(
a_, a_, SORTING_BITS, stash_size=20, variant=POHVariant.PATH
)
stop_fancy_timer(id)
lib.print_ln(
"[Sorting (POH) constant stash size] Sorted array: %s", a_.reveal()
)