1 /** \example benchmark/benchmark_rmf.cpp
2  * \brief Benchmark typical creation, traversal and loading with different RMF
3  *        backends.
4  *
5  * Copyright 2007-2021 IMP Inventors. All rights reserved.
6  */
7 
8 #include <boost/iterator/iterator_facade.hpp>
9 #include <boost/filesystem/operations.hpp>
10 #include <boost/timer.hpp>
11 #include <exception>
12 #include <iostream>
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"
26 #include "RMF/infrastructure_macros.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 
show_size(unsigned int sz)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 
benchmark_size(std::string path,std::string type)48 void benchmark_size(std::string path, std::string type) {
49   unsigned int size = 0;
50   if (boost::filesystem::is_directory(path)) {
51     for (boost::filesystem::directory_iterator it(path);
52          it != boost::filesystem::directory_iterator(); it++) {
53       size += boost::filesystem::file_size(*it);
54     }
55   } else {
56     size = boost::filesystem::file_size(path);
57   }
58   std::cout << type << ", size, " << show_size(size) << ", " << size
59             << std::endl;
60 }
61 
create_residue(RMF::NodeHandle nh,RMF::decorator::AtomFactory af,RMF::decorator::ParticleFactory pf)62 std::size_t create_residue(RMF::NodeHandle nh, RMF::decorator::AtomFactory af,
63                            RMF::decorator::ParticleFactory pf) {
64   std::size_t total_size = 0;
65   for (unsigned int i = 0; i < 2 * scale; ++i) {
66     RMF::NodeHandle child = nh.add_child("CA", RMF::REPRESENTATION);
67     pf.get(child).set_static_mass(1);
68     pf.get(child).set_static_radius(1.0 + i / 18.77);
69     af.get(child).set_static_element(7);
70     total_size += sizeof(int) * 1 + sizeof(float) * 2;
71   }
72   return total_size;
73 }
create_chain(RMF::NodeHandle nh,RMF::decorator::ResidueFactory rf,RMF::decorator::AtomFactory af,RMF::decorator::ParticleFactory pf)74 std::size_t create_chain(RMF::NodeHandle nh, RMF::decorator::ResidueFactory rf,
75                          RMF::decorator::AtomFactory af,
76                          RMF::decorator::ParticleFactory pf) {
77   std::size_t total_size = 0;
78   for (unsigned int i = 0; i < 60 * scale; ++i) {
79     std::ostringstream oss;
80     oss << i;
81     RMF::NodeHandle child = nh.add_child(oss.str(), RMF::REPRESENTATION);
82     rf.get(child).set_static_residue_type("cys");
83     rf.get(child).set_static_residue_index(i);
84     total_size += sizeof(int) + 4;
85     total_size += create_residue(child, af, pf);
86   }
87   return total_size;
88 }
create_hierarchy(RMF::FileHandle file)89 std::size_t create_hierarchy(RMF::FileHandle file) {
90   RMF::decorator::ChainFactory cf(file);
91   RMF::decorator::AtomFactory af(file);
92   RMF::decorator::ResidueFactory rf(file);
93   RMF::decorator::ParticleFactory pf(file);
94   RMF::NodeHandle n = file.get_root_node();
95   std::size_t total_size = 0;
96   for (unsigned int i = 0; i < 3 * scale; ++i) {
97     std::ostringstream oss;
98     oss << i;
99     RMF::NodeHandle child = n.add_child(oss.str(), RMF::REPRESENTATION);
100     cf.get(child).set_static_chain_id(oss.str());
101     total_size += oss.str().size();
102     total_size += create_chain(child, rf, af, pf);
103   }
104   return total_size;
105 }
106 
create_frame(RMF::FileHandle fh,RMF::decorator::ParticleFactory ipf,const RMF::NodeIDs & atoms,int frame)107 std::pair<double, std::size_t> create_frame(RMF::FileHandle fh,
108                                             RMF::decorator::ParticleFactory ipf,
109                                             const RMF::NodeIDs& atoms,
110                                             int frame) {
111   RMF::Vector3 ret(0, 0, 0);
112   std::size_t total_size = 0;
113   RMF_FOREACH(RMF::NodeID n, atoms) {
114     RMF::Vector3 v((n.get_index() + 0 + frame) / 17.0,
115                    (n.get_index() + 1 + frame) / 19.0,
116                    (n.get_index() + 2 + frame) / 23.0);
117     ret[0] += v[0];
118     ret[1] += v[1];
119     ret[2] += v[2];
120     ipf.get(fh.get_node(n)).set_frame_coordinates(v);
121     total_size += sizeof(float) * 3;
122   }
123   return std::make_pair(ret[0] + ret[1] + ret[2], total_size);
124 }
125 
create(RMF::FileHandle file,RMF::NodeIDs & atoms)126 boost::tuple<std::size_t> create(RMF::FileHandle file, RMF::NodeIDs& atoms) {
127   std::size_t hierarchy_size = create_hierarchy(file);
128   RMF_FOREACH(RMF::NodeID n, file.get_node_ids()) {
129     if (file.get_node(n).get_children().empty()) {
130       atoms.push_back(n);
131     }
132   }
133   return boost::make_tuple(hierarchy_size);
134 }
135 
create_frames(RMF::FileHandle file,const RMF::NodeIDs & atoms)136 boost::tuple<double, std::size_t> create_frames(RMF::FileHandle file,
137                                                 const RMF::NodeIDs& atoms) {
138   RMF::decorator::ParticleFactory ipf(file);
139   double check_value = 0;
140   std::size_t frame_size = 0;
141   for (unsigned int i = 0; i < 20; ++i) {
142     file.add_frame("frame", RMF::FRAME);
143     std::pair<double, std::size_t> cur = create_frame(file, ipf, atoms, i);
144     check_value += cur.first;
145     frame_size += cur.second;
146   }
147   return boost::make_tuple(check_value, frame_size);
148 }
149 
traverse(RMF::FileConstHandle file)150 double traverse(RMF::FileConstHandle file) {
151   double ret = 0;
152   RMF::NodeConstHandles queue(1, file.get_root_node());
153   RMF::decorator::ParticleFactory ipcf(file);
154   do {
155     RMF::NodeConstHandle cur = queue.back();
156     queue.pop_back();
157     if (ipcf.get_is(cur)) {
158       ret += ipcf.get(cur).get_radius();
159     }
160     RMF::NodeConstHandles children = cur.get_children();
161     queue.insert(queue.end(), children.begin(), children.end());
162   } while (!queue.empty());
163   return ret;
164 }
165 
load(RMF::FileConstHandle file,const RMF::NodeIDs & nodes)166 double load(RMF::FileConstHandle file, const RMF::NodeIDs& nodes) {
167   RMF::decorator::IntermediateParticleFactory ipcf(file);
168   RMF::Vector3 v(0, 0, 0);
169   RMF_FOREACH(RMF::FrameID fr, file.get_frames()) {
170     file.set_current_frame(fr);
171     RMF_FOREACH(RMF::NodeID n, nodes) {
172       RMF::Vector3 cur = ipcf.get(file.get_node(n)).get_coordinates();
173       v[0] += cur[0];
174       v[1] += cur[1];
175       v[2] += cur[2];
176     }
177   }
178   return v[0] + v[1] + v[2];
179 }
180 
benchmark_create(RMF::FileHandle file,std::string type)181 std::pair<std::size_t, std::size_t> benchmark_create(RMF::FileHandle file,
182                                                      std::string type) {
183   RMF::NodeIDs atoms;
184   boost::timer timer;
185   boost::tuple<std::size_t> cur = create(file, atoms);
186   std::cout << type << ", create, " << timer.elapsed() << ", " << cur.get<0>()
187             << std::endl;
188   boost::timer frame_timer;
189   boost::tuple<double, std::size_t> frames = create_frames(file, atoms);
190   std::cout << type << ", create frame, " << frame_timer.elapsed() / 20.0
191             << ", " << frames.get<0>() << std::endl;
192   return std::make_pair(cur.get<0>(), frames.get<1>());
193 }
194 
benchmark_traverse(RMF::FileConstHandle file,std::string type)195 void benchmark_traverse(RMF::FileConstHandle file, std::string type) {
196   file.set_current_frame(RMF::FrameID(0));
197   boost::timer timer;
198   double count = 0;
199   double t;
200   while (timer.elapsed() < 1) {
201     t = traverse(file);
202     ++count;
203   }
204   std::cout << type << ", traverse, " << timer.elapsed() / count << ", " << t
205             << std::endl;
206 }
207 
benchmark_load(RMF::FileConstHandle file,std::string type)208 void benchmark_load(RMF::FileConstHandle file, std::string type) {
209   RMF::NodeIDs nodes;
210   RMF::decorator::ParticleFactory ipcf(file);
211   RMF_FOREACH(RMF::NodeID n, file.get_node_ids()) {
212     if (ipcf.get_is(file.get_node(n))) nodes.push_back(n);
213   }
214   boost::timer timer;
215   double dist = load(file, nodes);
216   std::cout << type << ", load, " << timer.elapsed() / 20.0 << ", " << dist
217             << std::endl;
218 }
219 
benchmark_open(std::string path,std::string type)220 RMF::FileConstHandle benchmark_open(std::string path, std::string type) {
221   boost::timer timer;
222   RMF::FileConstHandle ret;
223   double count = 0;
224   while (timer.elapsed() < 1) {
225     ret = RMF::open_rmf_file_read_only(path);
226     ++count;
227   }
228   std::cout << type << ", open, " << timer.elapsed() / count << ", 0"
229             << std::endl;
230   return ret;
231 }
232 }  // namespace
233 
main(int,char **)234 int main(int, char**) {
235   try {
236     RMF::set_log_level("Off");
237     std::string name_base = RMF::internal::get_unique_path();
238 #ifndef NDEBUG
239     std::cout << name_base << std::endl;
240 #endif
241     {
242       const std::string name = name_base + ".rmf";
243       {
244         RMF::FileHandle fh = RMF::create_rmf_file(name);
245         std::pair<std::size_t, std::size_t> sizes = benchmark_create(fh, "rmf");
246         std::cout << "raw, total, " << show_size(sizes.first + sizes.second)
247                   << ", " << (sizes.first + sizes.second) << std::endl;
248         std::cout << "raw, frame, " << show_size(sizes.second) << ", "
249                   << sizes.second << std::endl;
250       }
251       {
252         RMF::FileConstHandle fh = benchmark_open(name, "rmf");
253         benchmark_traverse(fh, "rmf");
254         benchmark_load(fh, "rmf");
255       }
256       benchmark_size(name, "rmf");
257     }
258     {
259       const std::string name = name_base + ".rmfz";
260       {
261         RMF::FileHandle fh = RMF::create_rmf_file(name);
262         benchmark_create(fh, "rmfz");
263       }
264       {
265         RMF::FileConstHandle fh = benchmark_open(name, "rmfz");
266         benchmark_traverse(fh, "rmfz");
267         benchmark_load(fh, "rmfz");
268       }
269       benchmark_size(name, "rmfz");
270     }
271     {
272       RMF::BufferHandle buffer;
273       {
274         RMF::FileHandle fh = RMF::create_rmf_buffer(buffer);
275         benchmark_create(fh, "buffer");
276       }
277       {
278         boost::timer timer;
279         RMF::FileConstHandle fh = RMF::open_rmf_buffer_read_only(buffer);
280         std::cout << "buffer"
281                   << ", open, " << timer.elapsed() << ", 0" << std::endl;
282         benchmark_traverse(fh, "buffer");
283         benchmark_load(fh, "buffer");
284       }
285     }
286   }
287   catch (const std::exception& e) {
288     std::cerr << "Exception thrown: " << e.what() << std::endl;
289   }
290   return 0;
291 }
292