Clearmatics Libff  0.1
C++ library for Finite Fields and Elliptic Curves
Classes | Typedefs | Functions
profile_algebra_groups_read.cpp File Reference
#include "libff/algebra/curves/alt_bn128/alt_bn128_pp.hpp"
#include "libff/algebra/curves/bls12_377/bls12_377_pp.hpp"
#include "libff/algebra/curves/curve_serialization.hpp"
#include "libff/common/profiling.hpp"
#include <aio.h>
#include <exception>
#include <fcntl.h>
#include <fstream>
#include <map>
#include <sys/mman.h>
#include <sys/stat.h>
#include <thread>
#include <unistd.h>
Include dependency graph for profile_algebra_groups_read.cpp:

Go to the source code of this file.

Classes

class  batched_aio_reader< BatchSize >
 
class  profile_selector< GroupT >
 

Typedefs

typedef void(* profile_fn) (const std::string &, const size_t)
 

Functions

std::string get_filename (const std::string &identifier)
 
template<typename GroupT , form_t Form = form_montgomery, compression_t Comp = compression_off>
bool ensure_group_elements_file_uncompressed (const std::string &identifier)
 Returns true if the file was already present. More...
 
template<typename GroupT , form_t Form = form_montgomery, compression_t Comp = compression_off>
void profile_group_read_sequential_uncompressed (const std::string &identifier, const size_t)
 
template<typename GroupT , form_t Form = form_montgomery, compression_t Comp = compression_off>
void profile_group_read_random_seek_uncompressed (const std::string &identifier)
 
template<typename GroupT , form_t Form = form_montgomery, compression_t Comp = compression_off>
void profile_group_read_random_seek_ordered_uncompressed (const std::string &identifier, const size_t interval)
 
template<typename GroupT >
void profile_group_read_random_seek_fd_uncompressed (const std::string &identifier, const size_t)
 
template<typename GroupT >
void profile_group_read_random_seek_fd_ordered_uncompressed (const std::string &identifier, const size_t)
 
template<typename GroupT >
void profile_group_read_random_seek_mmap_ordered_uncompressed (const std::string &identifier, const size_t interval)
 
void cb_init (aiocb *cb, int fd, size_t offset_bytes, size_t size_bytes, void *dest)
 
void cb_enqueue (aiocb *cb)
 
ssize_t cb_wait (aiocb *cb)
 
template<typename GroupT >
void profile_group_read_random_batch_aio_ordered_uncompressed (const std::string &identifier, const size_t interval)
 
void usage (const char *const argv0)
 
template<typename GroupT >
void run_profile (const std::string &profile, const std::string &identifier, const size_t interval)
 
int main (const int argc, char const *const *const argv)
 

Typedef Documentation

◆ profile_fn

typedef void(* profile_fn) (const std::string &, const size_t)

Definition at line 560 of file profile_algebra_groups_read.cpp.

Function Documentation

◆ cb_enqueue()

void cb_enqueue ( aiocb *  cb)

Definition at line 353 of file profile_algebra_groups_read.cpp.

354 {
355  const int r = aio_read(cb);
356  if (0 == r) {
357  // std::cout << "cb_wait: enqueued\n";
358  return;
359  }
360 
361  throw std::runtime_error(
362  std::string("error from aio_read: ") + strerror(errno));
363 }

◆ cb_init()

void cb_init ( aiocb *  cb,
int  fd,
size_t  offset_bytes,
size_t  size_bytes,
void *  dest 
)

Definition at line 338 of file profile_algebra_groups_read.cpp.

340 {
341  // std::cout << "cb_init: " << fd << ", off: " << offset_bytes << ", size: "
342  // << size_bytes << ", dst: " << dest << "\n";
343 
344  memset(cb, 0, sizeof(aiocb));
345  cb->aio_fildes = fd;
346  cb->aio_offset = offset_bytes;
347  cb->aio_buf = dest;
348  cb->aio_nbytes = size_bytes;
349  cb->aio_sigevent.sigev_notify = SIGEV_NONE;
350  cb->aio_lio_opcode = LIO_READ;
351 }
Here is the caller graph for this function:

◆ cb_wait()

ssize_t cb_wait ( aiocb *  cb)

Definition at line 365 of file profile_algebra_groups_read.cpp.

366 {
367  int err;
368  for (;;) {
369  err = aio_error(cb);
370  if (err == EINPROGRESS) {
371  std::this_thread::yield();
372  // sleep(0);
373  continue;
374  }
375 
376  const ssize_t ret = aio_return(cb);
377  if (ret >= 0) {
378  // std::cout << "cb_wait: done\n";
379  return ret;
380  }
381 
382  if (err == ECANCELED) {
383  throw std::runtime_error("aio_error: cancelled");
384  }
385 
386  throw std::runtime_error(
387  std::string("error from aio_error: ") + strerror(errno));
388  }
389 }
Here is the caller graph for this function:

◆ ensure_group_elements_file_uncompressed()

template<typename GroupT , form_t Form = form_montgomery, compression_t Comp = compression_off>
bool ensure_group_elements_file_uncompressed ( const std::string &  identifier)

Returns true if the file was already present.

Definition at line 34 of file profile_algebra_groups_read.cpp.

35 {
36  const std::string filename = get_filename(identifier);
37 
38  // If file doesn't exist, create it.
39  struct stat s;
40  if (stat(filename.c_str(), &s)) {
41  std::cout << " File '" << filename.c_str()
42  << "' does not exist. Creating ... ";
43  std::flush(std::cout);
44 
45  // Fill a buffer with random elements
46  std::vector<GroupT> elements;
47  elements.reserve(NUM_DIFFERENT_ELEMENTS);
48  for (size_t i = 0; i < NUM_DIFFERENT_ELEMENTS; ++i) {
49  elements.push_back(GroupT::random_element());
50  }
51 
52  // Use the buffer to fill the file
53  std::ofstream out_s(
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>(
57  elements[i % NUM_DIFFERENT_ELEMENTS], out_s);
58  }
59  out_s.close();
60 
61  std::cout << "Created\n";
62  return false;
63  }
64 
65  return true;
66 }
Here is the call graph for this function:

◆ get_filename()

std::string get_filename ( const std::string &  identifier)

Definition at line 24 of file profile_algebra_groups_read.cpp.

25 {
26  return "group_elements_uncompressed_" + identifier + ".bin";
27 }
Here is the caller graph for this function:

◆ main()

int main ( const int  argc,
char const *const *const  argv 
)

Definition at line 622 of file profile_algebra_groups_read.cpp.

623 {
624  std::string profile = "all";
625  size_t sparse_interval = MAX_SPARSE_ELEMENT_INTERVAL;
626 
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")) {
632  profile = argv[++i];
633  } else {
634  usage(argv[0]);
635  return 1;
636  }
637  }
638 
639  if (sparse_interval > MAX_SPARSE_ELEMENT_INTERVAL) {
640  throw std::runtime_error("invalid interval");
641  }
642 
643  // Some configurations are disabled for now.
644 
645  std::cout << "alt_bn128_pp\n";
646  alt_bn128_pp::init_public_params();
647  run_profile<alt_bn128_G1>(profile, "alt_bn128_G1", sparse_interval);
648  run_profile<alt_bn128_G2>(profile, "alt_bn128_G2", sparse_interval);
649 
650  // For now (to avoid too many large data files and very long runtimes, this
651  // is disabled. Uncomment to run for bls12-377.
652 
653  // std::cout << "bls12_377_pp\n";
654  // bls12_377_pp::init_public_params();
655  // run_profile<bls12_377_G1>("bls12_377_G1");
656  // run_profile<bls12_377_G2>("bls12_377_G2");
657 
658  return 0;
659 }

◆ profile_group_read_random_batch_aio_ordered_uncompressed()

template<typename GroupT >
void profile_group_read_random_batch_aio_ordered_uncompressed ( const std::string &  identifier,
const size_t  interval 
)

Perform async reads of single group elements, with some (average) interval between reads on disk, using the aio_* family of functions. Multple aio requests are kept in-flight at the same time.

Definition at line 482 of file profile_algebra_groups_read.cpp.

484 {
485  const std::string filename = get_filename(identifier);
486 
487  // Perform reads from a set of orderd, but random, locations where the
488  // average interval between read locations (the sparsity) is `interval`.
489  // Treat the file as being divided into sections, each of size `interval`.
490  // For each section, we perform a single read from a random offset.
491 
492  // Preecompute the random offsets
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);
497  }
498 
499  int fd = open(filename.c_str(), O_RDONLY);
500  if (fd < 0) {
501  throw std::runtime_error("failed to open " + filename);
502  }
503 
504  const size_t BATCH_SIZE = 8;
505  static_assert(
506  0 == (NUM_ELEMENTS_TO_READ % BATCH_SIZE), "invalid batch size");
508 
509  GroupT dest1[BATCH_SIZE];
510  GroupT dest2[BATCH_SIZE];
511  const size_t size_on_disk = 2 * sizeof(dest1[0].X);
512 
513  GroupT *cur_dest = dest1;
514  GroupT *next_dest = dest2;
515 
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";
519 
520  {
521  enter_block("Read group elements profiling");
522 
523  size_t i = 0;
524 
525  // Enqueue first requests
526  for (size_t j = 0; j < BATCH_SIZE; ++j) {
527  reader.enqueue_read_first_batch(
528  section_offsets[i + j] * size_on_disk,
529  size_on_disk,
530  cur_dest + j);
531  }
532  i += BATCH_SIZE;
533 
534  // Enqueue all requests
535  for (; i < NUM_ELEMENTS_TO_READ; i += BATCH_SIZE) {
536  // Enqueue next batch
537  for (size_t j = 0; j < BATCH_SIZE; ++j) {
538  reader.enqueue_read(
539  ((i + j) * interval + section_offsets[i + j]) *
540  size_on_disk,
541  size_on_disk,
542  cur_dest + j);
543  }
544 
545  // Wait for current and process
546  reader.wait_last_read();
547 
548  // Swap (at which point, cur_cb is the next element to wait for, and
549  // next_cb is unused).
550  std::swap(cur_dest, next_dest);
551  }
552 
553  // Wait for last request
554  reader.wait_last_read();
555 
556  leave_block("Read group elements profiling");
557  }
558 }
Here is the call graph for this function:

◆ profile_group_read_random_seek_fd_ordered_uncompressed()

template<typename GroupT >
void profile_group_read_random_seek_fd_ordered_uncompressed ( const std::string &  identifier,
const  size_t 
)

Definition at line 239 of file profile_algebra_groups_read.cpp.

241 {
242  const std::string filename = get_filename(identifier);
243 
244  // Measure time taken to read the file
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";
248  {
249  std::vector<GroupT> elements;
250  elements.resize(NUM_DIFFERENT_ELEMENTS);
251 
252  int f = open(filename.c_str(), O_RDONLY);
253  if (f < 0) {
254  throw std::runtime_error("failed to open " + filename);
255  }
256 
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;
260  {
261  enter_block("Read group elements profiling");
262  for (size_t i = 0; i < NUM_ELEMENTS_TO_READ; ++i) {
263  const size_t different_element_idx = i % NUM_DIFFERENT_ELEMENTS;
264  const size_t offset = i * element_interval_bytes;
265  GroupT &dest_element = elements[different_element_idx];
266 
267  lseek(f, offset, SEEK_SET);
268  read(f, &dest_element, element_size_on_disk);
269  }
270  leave_block("Read group elements profiling");
271  }
272 
273  close(f);
274  }
275 }
Here is the call graph for this function:

◆ profile_group_read_random_seek_fd_uncompressed()

template<typename GroupT >
void profile_group_read_random_seek_fd_uncompressed ( const std::string &  identifier,
const  size_t 
)

Definition at line 192 of file profile_algebra_groups_read.cpp.

194 {
195  const std::string filename = get_filename(identifier);
196 
197  // Create a set of random indices. The i-th index to read from will be:
198  // (i + indices[i % NUM_DIFFERENT_ELEMENTS]) % NUM_ELEMENTS_IN_FILE
199  std::vector<size_t> indices;
200  indices.reserve(NUM_DIFFERENT_ELEMENTS);
201  for (size_t i = 0; i < NUM_DIFFERENT_ELEMENTS; ++i) {
202  indices.push_back(rand() % NUM_ELEMENTS_IN_FILE);
203  }
204 
205  // Measure time taken to read the 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";
209  {
210  std::vector<GroupT> elements;
211  elements.resize(NUM_DIFFERENT_ELEMENTS);
212 
213  int f = open(filename.c_str(), O_RDONLY);
214  if (f < 0) {
215  throw std::runtime_error("failed to open " + filename);
216  }
217 
218  const size_t element_size_on_disk = 2 * sizeof(elements[0].X);
219  {
220  enter_block("Read group elements profiling");
221  for (size_t i = 0; i < NUM_ELEMENTS_TO_READ; ++i) {
222  const size_t different_element_idx = i % NUM_DIFFERENT_ELEMENTS;
223  const size_t idx =
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];
227 
228  lseek(f, offset, SEEK_SET);
229  read(f, &dest_element, element_size_on_disk);
230  }
231  leave_block("Read group elements profiling");
232  }
233 
234  close(f);
235  }
236 }
Here is the call graph for this function:

◆ profile_group_read_random_seek_mmap_ordered_uncompressed()

template<typename GroupT >
void profile_group_read_random_seek_mmap_ordered_uncompressed ( const std::string &  identifier,
const size_t  interval 
)

Definition at line 278 of file profile_algebra_groups_read.cpp.

280 {
281  const std::string filename = get_filename(identifier);
282 
283  // Read sparse elements from a mem-mapped file, ensuring we always proceed
284  // forwards.
285 
286  // Measure time taken to read the file
287  std::cout << " Random Access MMap (Ordered) '" << filename.c_str() << "' ("
288  << NUM_ELEMENTS_TO_READ << " elements, interval: " << interval
289  << ") ...\n";
290  {
291  std::vector<GroupT> elements;
292  elements.resize(NUM_DIFFERENT_ELEMENTS);
293 
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;
296 
297  int fd = open(filename.c_str(), O_RDONLY);
298  if (fd < 0) {
299  throw std::runtime_error("failed to open " + filename);
300  }
301 
302  const void *file_base = mmap(
303  nullptr,
304  file_size,
305  PROT_READ,
306  MAP_PRIVATE /* | MAP_NOCACHE */,
307  fd,
308  0);
309  if (MAP_FAILED == file_base) {
310  throw std::runtime_error(
311  std::string("mmap failed: ") + strerror(errno));
312  }
313 
314  const size_t element_interval_bytes = element_size_on_disk * interval;
315 
316  {
317  enter_block("Read group elements profiling");
318  for (size_t i = 0; i < NUM_ELEMENTS_TO_READ; ++i) {
319  const size_t different_element_idx = i % NUM_DIFFERENT_ELEMENTS;
320  const size_t offset = i * element_interval_bytes;
321  GroupT &dest_element = elements[different_element_idx];
322  const GroupT *src =
323  (const GroupT *)(const void *)((size_t)file_base + offset);
324 
325  dest_element.X = src->X;
326  dest_element.Y = src->Y;
327  }
328  leave_block("Read group elements profiling");
329  }
330 
331  if (0 != munmap((void *)file_base, file_size)) {
332  throw std::runtime_error("munmap failed");
333  }
334  close(fd);
335  }
336 }
Here is the call graph for this function:

◆ profile_group_read_random_seek_ordered_uncompressed()

template<typename GroupT , form_t Form = form_montgomery, compression_t Comp = compression_off>
void profile_group_read_random_seek_ordered_uncompressed ( const std::string &  identifier,
const size_t  interval 
)

Definition at line 155 of file profile_algebra_groups_read.cpp.

157 {
158  const std::string filename = get_filename(identifier);
159 
160  // Measure time taken to read the file
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";
164  {
165  std::vector<GroupT> elements;
166  elements.resize(NUM_DIFFERENT_ELEMENTS);
167 
168  std::ifstream in_s(
169  filename.c_str(), std::ios_base::in | std::ios_base::binary);
170  in_s.exceptions(
171  std::ios_base::eofbit | std::ios_base::badbit |
172  std::ios_base::failbit);
173 
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;
176  {
177  enter_block("Read group elements profiling");
178  for (size_t i = 0; i < NUM_ELEMENTS_TO_READ; ++i) {
179  const size_t different_element_idx = i % NUM_DIFFERENT_ELEMENTS;
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));
183  }
184  leave_block("Read group elements profiling");
185  }
186 
187  in_s.close();
188  }
189 }
Here is the call graph for this function:

◆ profile_group_read_random_seek_uncompressed()

template<typename GroupT , form_t Form = form_montgomery, compression_t Comp = compression_off>
void profile_group_read_random_seek_uncompressed ( const std::string &  identifier)

Definition at line 107 of file profile_algebra_groups_read.cpp.

108 {
109  const std::string filename = get_filename(identifier);
110 
111  // Create a set of random indices. The i-th index to read from will be:
112  // (i + indices[i % NUM_DIFFERENT_ELEMENTS]) % NUM_ELEMENTS_IN_FILE
113  std::vector<size_t> indices;
114  indices.reserve(NUM_DIFFERENT_ELEMENTS);
115  for (size_t i = 0; i < NUM_DIFFERENT_ELEMENTS; ++i) {
116  indices.push_back(rand() % NUM_ELEMENTS_IN_FILE);
117  }
118 
119  // Measure time taken to read the 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";
123  {
124  std::vector<GroupT> elements;
125  elements.resize(NUM_DIFFERENT_ELEMENTS);
126 
127  std::ifstream in_s(
128  filename.c_str(), std::ios_base::in | std::ios_base::binary);
129  in_s.exceptions(
130  std::ios_base::eofbit | std::ios_base::badbit |
131  std::ios_base::failbit);
132 
133  const size_t element_size_on_disk = 2 * sizeof(elements[0].X);
134  {
135  enter_block("Read group elements profiling");
136  for (size_t i = 0; i < NUM_ELEMENTS_TO_READ; ++i) {
137  const size_t different_element_idx = i % NUM_DIFFERENT_ELEMENTS;
138  const size_t idx =
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));
143  }
144  leave_block("Read group elements profiling");
145  }
146 
147  in_s.close();
148  }
149 }
Here is the call graph for this function:

◆ profile_group_read_sequential_uncompressed()

template<typename GroupT , form_t Form = form_montgomery, compression_t Comp = compression_off>
void profile_group_read_sequential_uncompressed ( const std::string &  identifier,
const  size_t 
)

Definition at line 72 of file profile_algebra_groups_read.cpp.

74 {
75  const std::string filename = get_filename(identifier);
76 
77  // Measure time taken to read the file
78  std::cout << " Sequential read '" << filename.c_str() << "' (expecting "
79  << std::to_string(NUM_ELEMENTS_TO_READ) << " elements ...\n";
80  {
81  std::vector<GroupT> elements;
82  elements.resize(NUM_DIFFERENT_ELEMENTS);
83 
84  std::ifstream in_s(
85  filename.c_str(), std::ios_base::in | std::ios_base::binary);
86  in_s.exceptions(
87  std::ios_base::eofbit | std::ios_base::badbit |
88  std::ios_base::failbit);
89 
90  {
91  enter_block("Read group elements profiling");
92  for (size_t i = 0; i < NUM_ELEMENTS_TO_READ; ++i) {
93  group_read<encoding_binary, Form, Comp>(
94  elements[i % NUM_DIFFERENT_ELEMENTS], in_s);
95  }
96  leave_block("Read group elements profiling");
97  }
98 
99  in_s.close();
100  }
101 }
Here is the call graph for this function:

◆ run_profile()

template<typename GroupT >
void run_profile ( const std::string &  profile,
const std::string &  identifier,
const size_t  interval 
)

Definition at line 593 of file profile_algebra_groups_read.cpp.

597 {
598  std::cout << "profile: " << profile << "\n";
599  std::cout << "identifier: " << identifier << "\n";
600 
601  if (!ensure_group_elements_file_uncompressed<GroupT>(identifier)) {
602  return;
603  }
604 
605  class profile_selector<GroupT> p;
606 
607  if (profile == "all") {
608  for (const auto &pair : p.s_profile_functions) {
609  run_profile<GroupT>(pair.first, identifier, interval);
610  }
611  return;
612  }
613 
614  auto it = p.s_profile_functions.find(profile);
615  if (it == p.s_profile_functions.end()) {
616  throw std::runtime_error(std::string("no such profile: ") + profile);
617  }
618 
619  it->second(identifier, interval);
620 }

◆ usage()

void usage ( const char *const  argv0)

Definition at line 581 of file profile_algebra_groups_read.cpp.

582 {
583  std::cout << "Usage: " << argv0 << " [flags]\n"
584  << "\n"
585  << "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";
590 }
Here is the caller graph for this function:
libff::enter_block
void enter_block(const std::string &msg, const bool indent)
Definition: profiling.cpp:271
profile_selector
Definition: profile_algebra_groups_read.cpp:562
usage
void usage(const char *const argv0)
Definition: profile_algebra_groups_read.cpp:581
batched_aio_reader
Definition: profile_algebra_groups_read.cpp:391
libff::leave_block
void leave_block(const std::string &msg, const bool indent)
Definition: profiling.cpp:305
NUM_DIFFERENT_ELEMENTS
constexpr size_t NUM_DIFFERENT_ELEMENTS
Definition: profile_multiexp.cpp:15
get_filename
std::string get_filename(const std::string &identifier)
Definition: profile_algebra_groups_read.cpp:24