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/version.hpp>
10 #include <boost/filesystem/operations.hpp>
11 #if BOOST_VERSION >= 107200
12 #include <boost/filesystem/directory.hpp>
13 #endif
14 #include <exception>
15 #include <iostream>
16 #include <chrono>
17 #include <string>
18 #include <vector>
19 
20 #include "RMF/BufferHandle.h"
21 #include "RMF/FileConstHandle.h"
22 #include "RMF/FileHandle.h"
23 #include "RMF/ID.h"
24 #include "RMF/NodeConstHandle.h"
25 #include "RMF/NodeHandle.h"
26 #include "RMF/Vector.h"
27 #include "RMF/decorator/physics.h"
28 #include "RMF/decorator/sequence.h"
29 #include "RMF/enums.h"
31 #include "RMF/log.h"
32 
33 namespace {
34 #ifndef NDEBUG
35 const int scale = 1;
36 #else
37 const int scale = 5;
38 #endif
39 
40 std::string show_size(unsigned int sz) {
41  std::ostringstream oss;
42  if (sz > 1000000) {
43  oss << sz / 1000000 << "M";
44  } else if (sz > 1000) {
45  oss << sz / 1000 << "k";
46  } else {
47  oss << sz << "b";
48  }
49  return oss.str();
50 }
51 
52 class Timer {
53  std::chrono::steady_clock::time_point start_time_;
54 public:
55  Timer() {
56  start_time_ = std::chrono::steady_clock::now();
57  }
58 
59  double elapsed() const {
60  auto end_time = std::chrono::steady_clock::now();
61  auto time_span = std::chrono::duration_cast<
62  std::chrono::duration<double> >(end_time - start_time_);
63  return time_span.count();
64  }
65 };
66 
67 void benchmark_size(std::string path, std::string type) {
68  unsigned int size = 0;
69  if (boost::filesystem::is_directory(path)) {
70  for (boost::filesystem::directory_iterator it(path);
71  it != boost::filesystem::directory_iterator(); it++) {
72  size += boost::filesystem::file_size(*it);
73  }
74  } else {
75  size = boost::filesystem::file_size(path);
76  }
77  std::cout << type << ", size, " << show_size(size) << ", " << size
78  << std::endl;
79 }
80 
81 std::size_t create_residue(RMF::NodeHandle nh, RMF::decorator::AtomFactory af,
83  std::size_t total_size = 0;
84  for (unsigned int i = 0; i < 2 * scale; ++i) {
86  pf.get(child).set_static_mass(1);
87  pf.get(child).set_static_radius(1.0 + i / 18.77);
88  af.get(child).set_static_element(7);
89  total_size += sizeof(int) * 1 + sizeof(float) * 2;
90  }
91  return total_size;
92 }
93 std::size_t create_chain(RMF::NodeHandle nh, RMF::decorator::ResidueFactory rf,
96  std::size_t total_size = 0;
97  for (unsigned int i = 0; i < 60 * scale; ++i) {
98  std::ostringstream oss;
99  oss << i;
100  RMF::NodeHandle child = nh.add_child(oss.str(), RMF::REPRESENTATION);
101  rf.get(child).set_static_residue_type("cys");
102  rf.get(child).set_static_residue_index(i);
103  total_size += sizeof(int) + 4;
104  total_size += create_residue(child, af, pf);
105  }
106  return total_size;
107 }
108 std::size_t create_hierarchy(RMF::FileHandle file) {
113  RMF::NodeHandle n = file.get_root_node();
114  std::size_t total_size = 0;
115  for (unsigned int i = 0; i < 3 * scale; ++i) {
116  std::ostringstream oss;
117  oss << i;
118  RMF::NodeHandle child = n.add_child(oss.str(), RMF::REPRESENTATION);
119  cf.get(child).set_static_chain_id(oss.str());
120  total_size += oss.str().size();
121  total_size += create_chain(child, rf, af, pf);
122  }
123  return total_size;
124 }
125 
126 std::pair<double, std::size_t> create_frame(RMF::FileHandle fh,
128  const RMF::NodeIDs& atoms,
129  int frame) {
130  RMF::Vector3 ret(0, 0, 0);
131  std::size_t total_size = 0;
132  for(RMF::NodeID n : atoms) {
133  RMF::Vector3 v((n.get_index() + 0 + frame) / 17.0,
134  (n.get_index() + 1 + frame) / 19.0,
135  (n.get_index() + 2 + frame) / 23.0);
136  ret[0] += v[0];
137  ret[1] += v[1];
138  ret[2] += v[2];
139  ipf.get(fh.get_node(n)).set_frame_coordinates(v);
140  total_size += sizeof(float) * 3;
141  }
142  return std::make_pair(ret[0] + ret[1] + ret[2], total_size);
143 }
144 
145 boost::tuple<std::size_t> create(RMF::FileHandle file, RMF::NodeIDs& atoms) {
146  std::size_t hierarchy_size = create_hierarchy(file);
147  for(RMF::NodeID n : file.get_node_ids()) {
148  if (file.get_node(n).get_children().empty()) {
149  atoms.push_back(n);
150  }
151  }
152  return boost::make_tuple(hierarchy_size);
153 }
154 
155 boost::tuple<double, std::size_t> create_frames(RMF::FileHandle file,
156  const RMF::NodeIDs& atoms) {
158  double check_value = 0;
159  std::size_t frame_size = 0;
160  for (unsigned int i = 0; i < 20; ++i) {
161  file.add_frame("frame", RMF::FRAME);
162  std::pair<double, std::size_t> cur = create_frame(file, ipf, atoms, i);
163  check_value += cur.first;
164  frame_size += cur.second;
165  }
166  return boost::make_tuple(check_value, frame_size);
167 }
168 
169 double traverse(RMF::FileConstHandle file) {
170  double ret = 0;
171  RMF::NodeConstHandles queue(1, file.get_root_node());
173  do {
174  RMF::NodeConstHandle cur = queue.back();
175  queue.pop_back();
176  if (ipcf.get_is(cur)) {
177  ret += ipcf.get(cur).get_radius();
178  }
179  RMF::NodeConstHandles children = cur.get_children();
180  queue.insert(queue.end(), children.begin(), children.end());
181  } while (!queue.empty());
182  return ret;
183 }
184 
185 double load(RMF::FileConstHandle file, const RMF::NodeIDs& nodes) {
187  RMF::Vector3 v(0, 0, 0);
188  for(RMF::FrameID fr : file.get_frames()) {
189  file.set_current_frame(fr);
190  for(RMF::NodeID n : nodes) {
191  RMF::Vector3 cur = ipcf.get(file.get_node(n)).get_coordinates();
192  v[0] += cur[0];
193  v[1] += cur[1];
194  v[2] += cur[2];
195  }
196  }
197  return v[0] + v[1] + v[2];
198 }
199 
200 std::pair<std::size_t, std::size_t> benchmark_create(RMF::FileHandle file,
201  std::string type) {
202  RMF::NodeIDs atoms;
203  Timer timer;
204  boost::tuple<std::size_t> cur = create(file, atoms);
205  std::cout << type << ", create, " << timer.elapsed() << ", " << cur.get<0>()
206  << std::endl;
207  Timer frame_timer;
208  boost::tuple<double, std::size_t> frames = create_frames(file, atoms);
209  std::cout << type << ", create frame, " << frame_timer.elapsed() / 20.0
210  << ", " << frames.get<0>() << std::endl;
211  return std::make_pair(cur.get<0>(), frames.get<1>());
212 }
213 
214 void benchmark_traverse(RMF::FileConstHandle file, std::string type) {
215  file.set_current_frame(RMF::FrameID(0));
216  Timer timer;
217  double count = 0;
218  double t;
219  while (timer.elapsed() < 1) {
220  t = traverse(file);
221  ++count;
222  }
223  std::cout << type << ", traverse, " << timer.elapsed() / count << ", " << t
224  << std::endl;
225 }
226 
227 void benchmark_load(RMF::FileConstHandle file, std::string type) {
228  RMF::NodeIDs nodes;
230  for(RMF::NodeID n : file.get_node_ids()) {
231  if (ipcf.get_is(file.get_node(n))) nodes.push_back(n);
232  }
233  Timer timer;
234  double dist = load(file, nodes);
235  std::cout << type << ", load, " << timer.elapsed() / 20.0 << ", " << dist
236  << std::endl;
237 }
238 
239 RMF::FileConstHandle benchmark_open(std::string path, std::string type) {
240  Timer timer;
242  double count = 0;
243  while (timer.elapsed() < 1) {
244  ret.close();
245  ret = RMF::open_rmf_file_read_only(path);
246  ++count;
247  }
248  std::cout << type << ", open, " << timer.elapsed() / count << ", 0"
249  << std::endl;
250  return ret;
251 }
252 } // namespace
253 
254 int main(int, char**) {
255  try {
256  RMF::set_log_level("Off");
257  std::string name_base = RMF::internal::get_unique_path();
258 #ifndef NDEBUG
259  std::cout << name_base << std::endl;
260 #endif
261  {
262  const std::string name = name_base + ".rmf";
263  {
265  std::pair<std::size_t, std::size_t> sizes = benchmark_create(fh, "rmf");
266  std::cout << "raw, total, " << show_size(sizes.first + sizes.second)
267  << ", " << (sizes.first + sizes.second) << std::endl;
268  std::cout << "raw, frame, " << show_size(sizes.second) << ", "
269  << sizes.second << std::endl;
270  }
271  {
272  RMF::FileConstHandle fh = benchmark_open(name, "rmf");
273  benchmark_traverse(fh, "rmf");
274  benchmark_load(fh, "rmf");
275  }
276  benchmark_size(name, "rmf");
277  }
278  {
279  const std::string name = name_base + ".rmfz";
280  {
282  benchmark_create(fh, "rmfz");
283  }
284  {
285  RMF::FileConstHandle fh = benchmark_open(name, "rmfz");
286  benchmark_traverse(fh, "rmfz");
287  benchmark_load(fh, "rmfz");
288  }
289  benchmark_size(name, "rmfz");
290  }
291 #if RMF_HAS_DEPRECATED_BACKENDS
292  {
293  const std::string name = name_base + ".rmf-hdf5";
294  {
296  benchmark_create(fh, "hdf5");
297  }
298  {
299  RMF::FileConstHandle fh = benchmark_open(name, "hdf5");
300  benchmark_traverse(fh, "hdf5");
301  benchmark_load(fh, "hdf5");
302  }
303  benchmark_size(name, "hdf5");
304  }
305 #endif
306  {
307  RMF::BufferHandle buffer;
308  {
310  benchmark_create(fh, "buffer");
311  }
312  {
313  Timer timer;
315  std::cout << "buffer"
316  << ", open, " << timer.elapsed() << ", 0" << std::endl;
317  benchmark_traverse(fh, "buffer");
318  benchmark_load(fh, "buffer");
319  }
320  }
321  }
322  catch (const std::exception& e) {
323  std::cerr << "Exception thrown: " << e.what() << std::endl;
324  }
325  return 0;
326 }
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