RMF
benchmark_rmf.cpp
1 /** \example benchmark/benchmark_rmf.cpp
2  * \brief Benchmark typical creation, traversal and loading with different RMF
3  * backends.
4  *
5  * Copyright 2007-2022 IMP Inventors. All rights reserved.
6  */
7 
8 #include <boost/iterator/iterator_facade.hpp>
9 #include <boost/filesystem/operations.hpp>
10 #include <boost/filesystem/directory.hpp>
11 #include <exception>
12 #include <iostream>
13 #include <chrono>
14 #include <string>
15 #include <vector>
16 
17 #include "RMF/BufferHandle.h"
18 #include "RMF/FileConstHandle.h"
19 #include "RMF/FileHandle.h"
20 #include "RMF/ID.h"
21 #include "RMF/NodeConstHandle.h"
22 #include "RMF/NodeHandle.h"
23 #include "RMF/Vector.h"
24 #include "RMF/decorator/physics.h"
25 #include "RMF/decorator/sequence.h"
26 #include "RMF/enums.h"
28 #include "RMF/log.h"
29 
30 namespace {
31 #ifndef NDEBUG
32 const int scale = 1;
33 #else
34 const int scale = 5;
35 #endif
36 
37 std::string show_size(unsigned int sz) {
38  std::ostringstream oss;
39  if (sz > 1000000) {
40  oss << sz / 1000000 << "M";
41  } else if (sz > 1000) {
42  oss << sz / 1000 << "k";
43  } else {
44  oss << sz << "b";
45  }
46  return oss.str();
47 }
48 
49 class Timer {
50  std::chrono::steady_clock::time_point start_time_;
51 public:
52  Timer() {
53  start_time_ = std::chrono::steady_clock::now();
54  }
55 
56  double elapsed() const {
57  auto end_time = std::chrono::steady_clock::now();
58  auto time_span = std::chrono::duration_cast<
59  std::chrono::duration<double> >(end_time - start_time_);
60  return time_span.count();
61  }
62 };
63 
64 void benchmark_size(std::string path, std::string type) {
65  unsigned int size = 0;
66  if (boost::filesystem::is_directory(path)) {
67  for (boost::filesystem::directory_iterator it(path);
68  it != boost::filesystem::directory_iterator(); it++) {
69  size += boost::filesystem::file_size(*it);
70  }
71  } else {
72  size = boost::filesystem::file_size(path);
73  }
74  std::cout << type << ", size, " << show_size(size) << ", " << size
75  << std::endl;
76 }
77 
78 std::size_t create_residue(RMF::NodeHandle nh, RMF::decorator::AtomFactory af,
80  std::size_t total_size = 0;
81  for (unsigned int i = 0; i < 2 * scale; ++i) {
83  pf.get(child).set_static_mass(1);
84  pf.get(child).set_static_radius(1.0 + i / 18.77);
85  af.get(child).set_static_element(7);
86  total_size += sizeof(int) * 1 + sizeof(float) * 2;
87  }
88  return total_size;
89 }
90 std::size_t create_chain(RMF::NodeHandle nh, RMF::decorator::ResidueFactory rf,
93  std::size_t total_size = 0;
94  for (unsigned int i = 0; i < 60 * scale; ++i) {
95  std::ostringstream oss;
96  oss << i;
97  RMF::NodeHandle child = nh.add_child(oss.str(), RMF::REPRESENTATION);
98  rf.get(child).set_static_residue_type("cys");
99  rf.get(child).set_static_residue_index(i);
100  total_size += sizeof(int) + 4;
101  total_size += create_residue(child, af, pf);
102  }
103  return total_size;
104 }
105 std::size_t create_hierarchy(RMF::FileHandle file) {
110  RMF::NodeHandle n = file.get_root_node();
111  std::size_t total_size = 0;
112  for (unsigned int i = 0; i < 3 * scale; ++i) {
113  std::ostringstream oss;
114  oss << i;
115  RMF::NodeHandle child = n.add_child(oss.str(), RMF::REPRESENTATION);
116  cf.get(child).set_static_chain_id(oss.str());
117  total_size += oss.str().size();
118  total_size += create_chain(child, rf, af, pf);
119  }
120  return total_size;
121 }
122 
123 std::pair<double, std::size_t> create_frame(RMF::FileHandle fh,
125  const RMF::NodeIDs& atoms,
126  int frame) {
127  RMF::Vector3 ret(0, 0, 0);
128  std::size_t total_size = 0;
129  for(RMF::NodeID n : atoms) {
130  RMF::Vector3 v((n.get_index() + 0 + frame) / 17.0,
131  (n.get_index() + 1 + frame) / 19.0,
132  (n.get_index() + 2 + frame) / 23.0);
133  ret[0] += v[0];
134  ret[1] += v[1];
135  ret[2] += v[2];
136  ipf.get(fh.get_node(n)).set_frame_coordinates(v);
137  total_size += sizeof(float) * 3;
138  }
139  return std::make_pair(ret[0] + ret[1] + ret[2], total_size);
140 }
141 
142 boost::tuple<std::size_t> create(RMF::FileHandle file, RMF::NodeIDs& atoms) {
143  std::size_t hierarchy_size = create_hierarchy(file);
144  for(RMF::NodeID n : file.get_node_ids()) {
145  if (file.get_node(n).get_children().empty()) {
146  atoms.push_back(n);
147  }
148  }
149  return boost::make_tuple(hierarchy_size);
150 }
151 
152 boost::tuple<double, std::size_t> create_frames(RMF::FileHandle file,
153  const RMF::NodeIDs& atoms) {
155  double check_value = 0;
156  std::size_t frame_size = 0;
157  for (unsigned int i = 0; i < 20; ++i) {
158  file.add_frame("frame", RMF::FRAME);
159  std::pair<double, std::size_t> cur = create_frame(file, ipf, atoms, i);
160  check_value += cur.first;
161  frame_size += cur.second;
162  }
163  return boost::make_tuple(check_value, frame_size);
164 }
165 
166 double traverse(RMF::FileConstHandle file) {
167  double ret = 0;
168  RMF::NodeConstHandles queue(1, file.get_root_node());
170  do {
171  RMF::NodeConstHandle cur = queue.back();
172  queue.pop_back();
173  if (ipcf.get_is(cur)) {
174  ret += ipcf.get(cur).get_radius();
175  }
176  RMF::NodeConstHandles children = cur.get_children();
177  queue.insert(queue.end(), children.begin(), children.end());
178  } while (!queue.empty());
179  return ret;
180 }
181 
182 double load(RMF::FileConstHandle file, const RMF::NodeIDs& nodes) {
184  RMF::Vector3 v(0, 0, 0);
185  for(RMF::FrameID fr : file.get_frames()) {
186  file.set_current_frame(fr);
187  for(RMF::NodeID n : nodes) {
188  RMF::Vector3 cur = ipcf.get(file.get_node(n)).get_coordinates();
189  v[0] += cur[0];
190  v[1] += cur[1];
191  v[2] += cur[2];
192  }
193  }
194  return v[0] + v[1] + v[2];
195 }
196 
197 std::pair<std::size_t, std::size_t> benchmark_create(RMF::FileHandle file,
198  std::string type) {
199  RMF::NodeIDs atoms;
200  Timer timer;
201  boost::tuple<std::size_t> cur = create(file, atoms);
202  std::cout << type << ", create, " << timer.elapsed() << ", " << cur.get<0>()
203  << std::endl;
204  Timer frame_timer;
205  boost::tuple<double, std::size_t> frames = create_frames(file, atoms);
206  std::cout << type << ", create frame, " << frame_timer.elapsed() / 20.0
207  << ", " << frames.get<0>() << std::endl;
208  return std::make_pair(cur.get<0>(), frames.get<1>());
209 }
210 
211 void benchmark_traverse(RMF::FileConstHandle file, std::string type) {
212  file.set_current_frame(RMF::FrameID(0));
213  Timer timer;
214  double count = 0;
215  double t;
216  while (timer.elapsed() < 1) {
217  t = traverse(file);
218  ++count;
219  }
220  std::cout << type << ", traverse, " << timer.elapsed() / count << ", " << t
221  << std::endl;
222 }
223 
224 void benchmark_load(RMF::FileConstHandle file, std::string type) {
225  RMF::NodeIDs nodes;
227  for(RMF::NodeID n : file.get_node_ids()) {
228  if (ipcf.get_is(file.get_node(n))) nodes.push_back(n);
229  }
230  Timer timer;
231  double dist = load(file, nodes);
232  std::cout << type << ", load, " << timer.elapsed() / 20.0 << ", " << dist
233  << std::endl;
234 }
235 
236 RMF::FileConstHandle benchmark_open(std::string path, std::string type) {
237  Timer timer;
239  double count = 0;
240  while (timer.elapsed() < 1) {
241  ret.close();
242  ret = RMF::open_rmf_file_read_only(path);
243  ++count;
244  }
245  std::cout << type << ", open, " << timer.elapsed() / count << ", 0"
246  << std::endl;
247  return ret;
248 }
249 } // namespace
250 
251 int main(int, char**) {
252  try {
253  RMF::set_log_level("Off");
254  std::string name_base = RMF::internal::get_unique_path();
255 #ifndef NDEBUG
256  std::cout << name_base << std::endl;
257 #endif
258  {
259  const std::string name = name_base + ".rmf";
260  {
262  std::pair<std::size_t, std::size_t> sizes = benchmark_create(fh, "rmf");
263  std::cout << "raw, total, " << show_size(sizes.first + sizes.second)
264  << ", " << (sizes.first + sizes.second) << std::endl;
265  std::cout << "raw, frame, " << show_size(sizes.second) << ", "
266  << sizes.second << std::endl;
267  }
268  {
269  RMF::FileConstHandle fh = benchmark_open(name, "rmf");
270  benchmark_traverse(fh, "rmf");
271  benchmark_load(fh, "rmf");
272  }
273  benchmark_size(name, "rmf");
274  }
275  {
276  const std::string name = name_base + ".rmfz";
277  {
279  benchmark_create(fh, "rmfz");
280  }
281  {
282  RMF::FileConstHandle fh = benchmark_open(name, "rmfz");
283  benchmark_traverse(fh, "rmfz");
284  benchmark_load(fh, "rmfz");
285  }
286  benchmark_size(name, "rmfz");
287  }
288 #if RMF_HAS_DEPRECATED_BACKENDS
289  {
290  const std::string name = name_base + ".rmf-hdf5";
291  {
293  benchmark_create(fh, "hdf5");
294  }
295  {
296  RMF::FileConstHandle fh = benchmark_open(name, "hdf5");
297  benchmark_traverse(fh, "hdf5");
298  benchmark_load(fh, "hdf5");
299  }
300  benchmark_size(name, "hdf5");
301  }
302 #endif
303  {
304  RMF::BufferHandle buffer;
305  {
307  benchmark_create(fh, "buffer");
308  }
309  {
310  Timer timer;
312  std::cout << "buffer"
313  << ", open, " << timer.elapsed() << ", 0" << std::endl;
314  benchmark_traverse(fh, "buffer");
315  benchmark_load(fh, "buffer");
316  }
317  }
318  }
319  catch (const std::exception& e) {
320  std::cerr << "Exception thrown: " << e.what() << std::endl;
321  }
322  return 0;
323 }
NodeHandle add_child(std::string name, NodeType t) const
ParticleConst get(NodeConstHandle nh) const
Definition: physics.h:193
FileConstHandle open_rmf_buffer_read_only(BufferConstHandle buffer)
Declaration of RMF::ID.
const NodeType REPRESENTATION
Represent part of a molecule.
Helper functions for manipulating RMF files.
A handle for a particular node in the hierarchy.
Definition: NodeHandle.h:60
ResidueConst get(NodeConstHandle nh) const
Definition: sequence.h:151
FileHandle create_rmf_buffer(BufferHandle buffer)
Create an RMF in a buffer.
FrameID add_frame(std::string name, FrameType t=FRAME) const
Add a frame and make it the current frame.
A handle for a particular node in a read-only hierarchy.
void set_log_level(std::string level)
const FrameType FRAME
A frame in a sequence of frames.
A handle for a read-only RMF file.
FileConstHandle open_rmf_file_read_only(std::string path)
FileHandle create_rmf_file(std::string path)
Create an RMF from a file system path.
A handle for an RMF file.
Definition: FileHandle.h:54
Declaration for RMF::FileHandle.
Represent coordinates.
Declaration of NodeConstHandle.
Declaration of NodeHandle.
The various enums used in RMF.
Manage a shared buffer for storing a RMF.
Definition: BufferHandle.h:22
std::vector< NodeConstHandle > NodeConstHandles
Pass a list of them.
NodeConstHandle get_root_node() const
Return the root of the hierarchy.
Helper functions for manipulating RMF files.
void close()
Explicitly close the file handle.
Handle read/write of Model data from/to files.
Functions and macros for logging.
Various general useful macros for IMP.
NodeHandle get_node(NodeID id) const
Return a NodeHandle from a NodeID.
std::vector< NodeID > NodeIDs
Definition: ID.h:113
AtomConst get(NodeConstHandle nh) const
Definition: physics.h:1023
Declare RMF::BufferHandle.
NodeHandle get_root_node() const
Return the root of the hierarchy stored in the file.
Definition: FileHandle.h:66