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