16 using namespace libff;
19 static const size_t NUM_ELEMENTS_TO_READ = 1024 * 1024;
20 static const size_t NUM_ELEMENTS_IN_FILE = 256 * NUM_ELEMENTS_TO_READ;
21 static const size_t MAX_SPARSE_ELEMENT_INTERVAL =
22 NUM_ELEMENTS_IN_FILE / NUM_ELEMENTS_TO_READ;
26 return "group_elements_uncompressed_" + identifier +
".bin";
40 if (stat(filename.c_str(), &s)) {
41 std::cout <<
" File '" << filename.c_str()
42 <<
"' does not exist. Creating ... ";
43 std::flush(std::cout);
46 std::vector<GroupT> elements;
49 elements.push_back(GroupT::random_element());
54 filename.c_str(), std::ios_base::out | std::ios_base::binary);
55 for (
size_t i = 0; i < NUM_ELEMENTS_IN_FILE; ++i) {
56 group_write<encoding_binary, Form, Comp>(
61 std::cout <<
"Created\n";
73 const std::string &identifier,
const size_t)
78 std::cout <<
" Sequential read '" << filename.c_str() <<
"' (expecting "
79 << std::to_string(NUM_ELEMENTS_TO_READ) <<
" elements ...\n";
81 std::vector<GroupT> elements;
85 filename.c_str(), std::ios_base::in | std::ios_base::binary);
87 std::ios_base::eofbit | std::ios_base::badbit |
88 std::ios_base::failbit);
92 for (
size_t i = 0; i < NUM_ELEMENTS_TO_READ; ++i) {
93 group_read<encoding_binary, Form, Comp>(
113 std::vector<size_t> indices;
116 indices.push_back(rand() % NUM_ELEMENTS_IN_FILE);
120 std::cout <<
" Random Access Read '" << filename.c_str() <<
"' ("
121 << std::to_string(NUM_ELEMENTS_TO_READ) <<
" of "
122 << std::to_string(NUM_ELEMENTS_IN_FILE) <<
" elements ...\n";
124 std::vector<GroupT> elements;
128 filename.c_str(), std::ios_base::in | std::ios_base::binary);
130 std::ios_base::eofbit | std::ios_base::badbit |
131 std::ios_base::failbit);
133 const size_t element_size_on_disk = 2 *
sizeof(elements[0].X);
136 for (
size_t i = 0; i < NUM_ELEMENTS_TO_READ; ++i) {
139 (indices[different_element_idx] + i) % NUM_ELEMENTS_IN_FILE;
140 const size_t offset = idx * element_size_on_disk;
141 group_read<encoding_binary, Form, Comp>(
142 elements[different_element_idx], in_s.seekg(offset));
156 const std::string &identifier,
const size_t interval)
161 std::cout <<
" Random Access Seeks (Ordered) '" << filename.c_str()
162 <<
"' (" << std::to_string(NUM_ELEMENTS_TO_READ) <<
" of "
163 << std::to_string(NUM_ELEMENTS_IN_FILE) <<
" elements ...\n";
165 std::vector<GroupT> elements;
169 filename.c_str(), std::ios_base::in | std::ios_base::binary);
171 std::ios_base::eofbit | std::ios_base::badbit |
172 std::ios_base::failbit);
174 const size_t element_size_on_disk = 2 *
sizeof(elements[0].X);
175 const size_t element_interval_bytes = element_size_on_disk * interval;
178 for (
size_t i = 0; i < NUM_ELEMENTS_TO_READ; ++i) {
180 const size_t offset = i * element_interval_bytes;
181 group_read<encoding_binary, Form, Comp>(
182 elements[different_element_idx], in_s.seekg(offset));
191 template<
typename GroupT>
193 const std::string &identifier,
const size_t)
199 std::vector<size_t> indices;
202 indices.push_back(rand() % NUM_ELEMENTS_IN_FILE);
206 std::cout <<
" Random Access Read '" << filename.c_str() <<
"' ("
207 << std::to_string(NUM_ELEMENTS_TO_READ) <<
" of "
208 << std::to_string(NUM_ELEMENTS_IN_FILE) <<
" elements ...\n";
210 std::vector<GroupT> elements;
213 int f = open(filename.c_str(), O_RDONLY);
215 throw std::runtime_error(
"failed to open " + filename);
218 const size_t element_size_on_disk = 2 *
sizeof(elements[0].X);
221 for (
size_t i = 0; i < NUM_ELEMENTS_TO_READ; ++i) {
224 (indices[different_element_idx] + i) % NUM_ELEMENTS_IN_FILE;
225 const size_t offset = idx * element_size_on_disk;
226 GroupT &dest_element = elements[different_element_idx];
228 lseek(f, offset, SEEK_SET);
229 read(f, &dest_element, element_size_on_disk);
238 template<
typename GroupT>
240 const std::string &identifier,
const size_t)
245 std::cout <<
" Random Access Read '" << filename.c_str() <<
"' ("
246 << std::to_string(NUM_ELEMENTS_TO_READ) <<
" of "
247 << std::to_string(NUM_ELEMENTS_IN_FILE) <<
" elements ...\n";
249 std::vector<GroupT> elements;
252 int f = open(filename.c_str(), O_RDONLY);
254 throw std::runtime_error(
"failed to open " + filename);
257 const size_t element_size_on_disk = 2 *
sizeof(elements[0].X);
258 const size_t element_interval_bytes =
259 element_size_on_disk * NUM_ELEMENTS_IN_FILE / NUM_ELEMENTS_TO_READ;
262 for (
size_t i = 0; i < NUM_ELEMENTS_TO_READ; ++i) {
264 const size_t offset = i * element_interval_bytes;
265 GroupT &dest_element = elements[different_element_idx];
267 lseek(f, offset, SEEK_SET);
268 read(f, &dest_element, element_size_on_disk);
277 template<
typename GroupT>
279 const std::string &identifier,
const size_t interval)
287 std::cout <<
" Random Access MMap (Ordered) '" << filename.c_str() <<
"' ("
288 << NUM_ELEMENTS_TO_READ <<
" elements, interval: " << interval
291 std::vector<GroupT> elements;
294 const size_t element_size_on_disk = 2 *
sizeof(elements[0].X);
295 const size_t file_size = NUM_ELEMENTS_IN_FILE * element_size_on_disk;
297 int fd = open(filename.c_str(), O_RDONLY);
299 throw std::runtime_error(
"failed to open " + filename);
302 const void *file_base = mmap(
309 if (MAP_FAILED == file_base) {
310 throw std::runtime_error(
311 std::string(
"mmap failed: ") + strerror(errno));
314 const size_t element_interval_bytes = element_size_on_disk * interval;
318 for (
size_t i = 0; i < NUM_ELEMENTS_TO_READ; ++i) {
320 const size_t offset = i * element_interval_bytes;
321 GroupT &dest_element = elements[different_element_idx];
323 (
const GroupT *)(
const void *)((size_t)file_base + offset);
325 dest_element.X = src->X;
326 dest_element.Y = src->Y;
331 if (0 != munmap((
void *)file_base, file_size)) {
332 throw std::runtime_error(
"munmap failed");
339 aiocb *cb,
int fd,
size_t offset_bytes,
size_t size_bytes,
void *dest)
344 memset(cb, 0,
sizeof(aiocb));
346 cb->aio_offset = offset_bytes;
348 cb->aio_nbytes = size_bytes;
349 cb->aio_sigevent.sigev_notify = SIGEV_NONE;
350 cb->aio_lio_opcode = LIO_READ;
355 const int r = aio_read(cb);
361 throw std::runtime_error(
362 std::string(
"error from aio_read: ") + strerror(errno));
370 if (err == EINPROGRESS) {
371 std::this_thread::yield();
376 const ssize_t ret = aio_return(cb);
382 if (err == ECANCELED) {
383 throw std::runtime_error(
"aio_error: cancelled");
386 throw std::runtime_error(
387 std::string(
"error from aio_error: ") + strerror(errno));
396 , _active_batch(_batch1_ptrs)
397 , _next_batch(_batch2_ptrs)
398 , _next_batch_size(0)
400 memset(_batch1, 0,
sizeof(_batch1));
401 memset(_batch2, 0,
sizeof(_batch2));
402 for (
size_t i = 0; i < BatchSize; ++i) {
403 _batch1_ptrs[i] = &_batch1[i];
404 _batch2_ptrs[i] = &_batch2[i];
409 size_t offset_bytes,
size_t size_bytes,
void *dest)
411 assert(_next_batch_size < BatchSize);
413 aiocb *cb = _next_batch[_next_batch_size];
414 cb_init(cb, _fd, offset_bytes, size_bytes, dest);
420 if (_next_batch_size == BatchSize) {
421 enqueue_next_batch();
423 std::swap(_active_batch, _next_batch);
424 _next_batch_size = 0;
430 assert(_next_batch_size < BatchSize);
432 aiocb *cb = _next_batch[_next_batch_size];
433 cb_init(cb, _fd, offset_bytes, size_bytes, dest);
436 if (_next_batch_size == BatchSize) {
437 enqueue_next_batch();
444 for (
size_t i = 0; i < BatchSize; ++i) {
445 int r =
cb_wait(_active_batch[i]);
447 throw std::runtime_error(
"bad read result");
455 std::swap(_active_batch, _next_batch);
456 _next_batch_size = 0;
462 int r = lio_listio(LIO_NOWAIT, _next_batch, BatchSize,
nullptr);
464 throw std::runtime_error(
"enqueue_batch error");
469 aiocb _batch1[BatchSize];
470 aiocb _batch2[BatchSize];
471 aiocb *_batch1_ptrs[BatchSize];
472 aiocb *_batch2_ptrs[BatchSize];
481 template<
typename GroupT>
483 const std::string &identifier,
const size_t interval)
493 std::vector<size_t> section_offsets;
494 section_offsets.reserve(NUM_ELEMENTS_TO_READ);
495 for (
size_t i = 0; i < NUM_ELEMENTS_TO_READ; ++i) {
496 section_offsets.push_back((
size_t)rand() * interval / RAND_MAX);
499 int fd = open(filename.c_str(), O_RDONLY);
501 throw std::runtime_error(
"failed to open " + filename);
504 const size_t BATCH_SIZE = 8;
506 0 == (NUM_ELEMENTS_TO_READ % BATCH_SIZE),
"invalid batch size");
509 GroupT dest1[BATCH_SIZE];
510 GroupT dest2[BATCH_SIZE];
511 const size_t size_on_disk = 2 *
sizeof(dest1[0].X);
513 GroupT *cur_dest = dest1;
514 GroupT *next_dest = dest2;
516 std::cout <<
" Deep Async Read '" << filename.c_str() <<
"' ("
517 << std::to_string(NUM_ELEMENTS_TO_READ) <<
" of "
518 << std::to_string(NUM_ELEMENTS_IN_FILE) <<
" elements ...\n";
526 for (
size_t j = 0; j < BATCH_SIZE; ++j) {
528 section_offsets[i + j] * size_on_disk,
535 for (; i < NUM_ELEMENTS_TO_READ; i += BATCH_SIZE) {
537 for (
size_t j = 0; j < BATCH_SIZE; ++j) {
539 ((i + j) * interval + section_offsets[i + j]) *
550 std::swap(cur_dest, next_dest);
560 typedef void (*
profile_fn)(
const std::string &,
const size_t);
565 std::map<std::string, profile_fn> s_profile_functions = {
566 {std::string(
"sequential"),
567 profile_group_read_sequential_uncompressed<GroupT>},
568 {std::string(
"stream"),
569 profile_group_read_random_seek_ordered_uncompressed<GroupT>},
571 profile_group_read_random_seek_fd_ordered_uncompressed<GroupT>},
572 {std::string(
"mmap"),
573 profile_group_read_random_seek_mmap_ordered_uncompressed<GroupT>},
575 profile_group_read_random_batch_aio_ordered_uncompressed<GroupT>},
576 {std::string(
"aio-batched"),
577 profile_group_read_random_batch_aio_ordered_uncompressed<GroupT>},
583 std::cout <<
"Usage: " << argv0 <<
" [flags]\n"
586 <<
" --interval <interval> Use sparse interval (default "
587 << MAX_SPARSE_ELEMENT_INTERVAL <<
")\n"
588 <<
" --profile <profile name> Run a specific profile "
589 "(default \"all\")\n";
592 template<
typename GroupT>
594 const std::string &profile,
595 const std::string &identifier,
596 const size_t interval)
598 std::cout <<
"profile: " << profile <<
"\n";
599 std::cout <<
"identifier: " << identifier <<
"\n";
601 if (!ensure_group_elements_file_uncompressed<GroupT>(identifier)) {
607 if (profile ==
"all") {
609 run_profile<GroupT>(pair.first, identifier, interval);
616 throw std::runtime_error(std::string(
"no such profile: ") + profile);
619 it->second(identifier, interval);
622 int main(
const int argc,
char const *
const *
const argv)
624 std::string profile =
"all";
625 size_t sparse_interval = MAX_SPARSE_ELEMENT_INTERVAL;
627 for (
size_t i = 1; i < (size_t)argc; ++i) {
628 const char *
const arg = argv[i];
629 if (!strcmp(arg,
"--interval")) {
630 sparse_interval = std::stoi(std::string(argv[++i]));
631 }
else if (!strcmp(arg,
"--profile")) {
639 if (sparse_interval > MAX_SPARSE_ELEMENT_INTERVAL) {
640 throw std::runtime_error(
"invalid interval");
645 std::cout <<
"alt_bn128_pp\n";
647 run_profile<alt_bn128_G1>(profile,
"alt_bn128_G1", sparse_interval);
648 run_profile<alt_bn128_G2>(profile,
"alt_bn128_G2", sparse_interval);