Logo AND Algorithmique Numérique Distribuée

Public GIT Repository
move creation and destruction logging to Class
[simgrid.git] / src / instr / instr_paje_containers.cpp
1 /* Copyright (c) 2010-2017. The SimGrid Team. All rights reserved.          */
2
3 /* This program is free software; you can redistribute it and/or modify it
4  * under the terms of the license (GNU LGPL) which comes with this package. */
5
6 #include "simgrid/s4u/Engine.hpp"
7 #include "simgrid/s4u/Host.hpp"
8 #include "src/instr/instr_private.hpp"
9 #include "surf/surf.h"
10 #include <sys/stat.h>
11 #ifdef WIN32
12 #include <direct.h> // _mkdir
13 #endif
14
15 #include <iomanip> /** std::setprecision **/
16 #include <sstream>
17 #include <unordered_map>
18
19 XBT_LOG_NEW_DEFAULT_SUBCATEGORY (instr_paje_containers, instr, "Paje tracing event system (containers)");
20
21 extern FILE* tracing_file;
22 extern std::map<container_t, FILE*> tracing_files; // TI specific
23 double prefix = 0.0;                               // TI specific
24
25 static container_t rootContainer = nullptr;    /* the root container */
26 static std::unordered_map<std::string, container_t> allContainers; /* all created containers indexed by name */
27 std::set<std::string> trivaNodeTypes;           /* all host types defined */
28 std::set<std::string> trivaEdgeTypes;           /* all link types defined */
29
30 long long int instr_new_paje_id ()
31 {
32   static long long int type_id = 0;
33   return type_id++;
34 }
35
36 container_t PJ_container_get_root()
37 {
38   return rootContainer;
39 }
40
41 void PJ_container_set_root (container_t root)
42 {
43   rootContainer = root;
44 }
45
46 namespace simgrid {
47 namespace instr {
48
49 Container::Container(std::string name, e_container_types kind, Container* father)
50     : name_(name), kind_(kind), father_(father)
51 {
52   static long long int container_id = 0;
53   id_                               = std::to_string(container_id); // id (or alias) of the container
54   container_id++;
55
56   if (father_) {
57     level_ = father_->level_ + 1;
58     XBT_DEBUG("new container %s, child of %s", name.c_str(), father->name_.c_str());
59   }
60
61   // Search for network_element_t for AS, ROUTER and HOST
62   // Name the kind of container. For AS otherwise, the name depends on its level
63   std::string typeNameBuff;
64   switch (kind_) {
65     case INSTR_AS:
66       netpoint_ = simgrid::s4u::Engine::getInstance()->getNetpointByNameOrNull(name);
67       xbt_assert(netpoint_, "Element '%s' not found", name.c_str());
68       typeNameBuff = std::string("L") + std::to_string(level_);
69       break;
70     case INSTR_ROUTER:
71       netpoint_ = simgrid::s4u::Engine::getInstance()->getNetpointByNameOrNull(name);
72       xbt_assert(netpoint_, "Element '%s' not found", name.c_str());
73       typeNameBuff = std::string("ROUTER");
74       break;
75     case INSTR_HOST:
76       netpoint_ = sg_host_by_name(name.c_str())->pimpl_netpoint;
77       xbt_assert(netpoint_, "Element '%s' not found", name.c_str());
78       typeNameBuff = std::string("HOST");
79       break;
80     case INSTR_LINK:
81       typeNameBuff = std::string("LINK");
82       break;
83     case INSTR_SMPI:
84       typeNameBuff = std::string("MPI");
85       break;
86     case INSTR_MSG_PROCESS:
87       typeNameBuff = std::string("MSG_PROCESS");
88       break;
89     case INSTR_MSG_VM:
90       typeNameBuff = std::string("MSG_VM");
91       break;
92     case INSTR_MSG_TASK:
93       typeNameBuff = std::string("MSG_TASK");
94       break;
95     default:
96       THROWF(tracing_error, 0, "new container kind is unknown.");
97       break;
98   }
99
100   if (father_) {
101     type_ = father_->type_->getChildOrNull(typeNameBuff);
102     if (type_ == nullptr) {
103       type_ = Type::containerNew(typeNameBuff.c_str(), father_->type_);
104     }
105     father_->children_.insert({name_, this});
106     logCreation();
107   } else if (kind_ == INSTR_AS) {
108     type_ = Type::containerNew("0", nullptr);
109   }
110
111   //register all kinds by name
112   if (not allContainers.emplace(name_, this).second) {
113     THROWF(tracing_error, 1, "container %s already present in allContainers data structure", name_.c_str());
114   }
115
116   XBT_DEBUG("Add container name '%s'", name_.c_str());
117
118   //register NODE types for triva configuration
119   if (kind_ == INSTR_HOST || kind_ == INSTR_LINK || kind_ == INSTR_ROUTER)
120     trivaNodeTypes.insert(type_->getName());
121 }
122
123 Container::~Container()
124 {
125   XBT_DEBUG("destroy container %s", name_.c_str());
126   // Begin with destroying my own children
127   for (auto child : children_) {
128     delete child.second;
129   }
130
131   // obligation to dump previous events because they might reference the container that is about to be destroyed
132   TRACE_last_timestamp_to_dump = surf_get_clock();
133   TRACE_paje_dump_buffer(1);
134
135   // trace my destruction
136   if (not TRACE_disable_destroy() && this != PJ_container_get_root()) {
137     // do not trace the container destruction if user requests or if the container is root
138     logDestruction();
139   }
140
141   // remove me from the allContainers data structure
142   allContainers.erase(name_);
143 }
144
145 Container* Container::byNameOrNull(std::string name)
146 {
147   auto cont = allContainers.find(name);
148   return cont == allContainers.end() ? nullptr : cont->second;
149 }
150
151 Container* Container::byName(std::string name)
152 {
153   Container* ret = Container::byNameOrNull(name);
154   if (ret == nullptr)
155     THROWF(tracing_error, 1, "container with name %s not found", name.c_str());
156
157   return ret;
158 }
159
160 void Container::removeFromParent()
161 {
162   if (father_) {
163     XBT_DEBUG("removeChildContainer (%s) FromContainer (%s) ", name_.c_str(), father_->name_.c_str());
164     father_->children_.erase(name_);
165   }
166 }
167
168 void Container::logCreation()
169 {
170   double timestamp = SIMIX_get_clock();
171   std::stringstream stream;
172
173   XBT_DEBUG("%s: event_type=%d, timestamp=%f", __FUNCTION__, simgrid::instr::PAJE_CreateContainer, timestamp);
174
175   if (instr_fmt_type == instr_fmt_paje) {
176     stream << std::fixed << std::setprecision(TRACE_precision());
177     stream << simgrid::instr::PAJE_CreateContainer;
178     stream << " ";
179     /* prevent 0.0000 in the trace - this was the behavior before the transition to c++ */
180     if (timestamp < 1e-12)
181       stream << 0;
182     else
183       stream << timestamp;
184     stream << " " << id_ << " " << type_->getId() << " " << father_->id_ << " \"" << name_ << "\"" << std::endl;
185     fprintf(tracing_file, "%s", stream.str().c_str());
186     XBT_DEBUG("Dump %s", stream.str().c_str());
187     stream.str("");
188     stream.clear();
189   } else if (instr_fmt_type == instr_fmt_TI) {
190     // if we are in the mode with only one file
191     static FILE* ti_unique_file = nullptr;
192
193     if (tracing_files.empty()) {
194       // generate unique run id with time
195       prefix = xbt_os_time();
196     }
197
198     if (not xbt_cfg_get_boolean("tracing/smpi/format/ti-one-file") || ti_unique_file == nullptr) {
199       char* folder_name = bprintf("%s_files", TRACE_get_filename());
200       char* filename    = bprintf("%s/%f_%s.txt", folder_name, prefix, name_.c_str());
201 #ifdef WIN32
202       _mkdir(folder_name);
203 #else
204       mkdir(folder_name, S_IRWXU | S_IRWXG | S_IRWXO);
205 #endif
206       ti_unique_file = fopen(filename, "w");
207       xbt_assert(ti_unique_file, "Tracefile %s could not be opened for writing: %s", filename, strerror(errno));
208       fprintf(tracing_file, "%s\n", filename);
209
210       xbt_free(folder_name);
211       xbt_free(filename);
212     }
213
214     tracing_files.insert({this, ti_unique_file});
215   } else {
216     THROW_IMPOSSIBLE;
217   }
218 }
219
220 void Container::logDestruction()
221 {
222   std::stringstream stream;
223   double timestamp = SIMIX_get_clock();
224
225   XBT_DEBUG("%s: event_type=%d, timestamp=%f", __FUNCTION__, simgrid::instr::PAJE_DestroyContainer, timestamp);
226
227   if (instr_fmt_type == instr_fmt_paje) {
228     stream << std::fixed << std::setprecision(TRACE_precision());
229     stream << simgrid::instr::PAJE_DestroyContainer;
230     stream << " ";
231     /* prevent 0.0000 in the trace - this was the behavior before the transition to c++ */
232     if (timestamp < 1e-12)
233       stream << 0;
234     else
235       stream << timestamp;
236     stream << " " << type_->getId() << " " << id_ << std::endl;
237     fprintf(tracing_file, "%s", stream.str().c_str());
238     XBT_DEBUG("Dump %s", stream.str().c_str());
239     stream.str("");
240     stream.clear();
241   } else if (instr_fmt_type == instr_fmt_TI) {
242     if (not xbt_cfg_get_boolean("tracing/smpi/format/ti-one-file") || tracing_files.size() == 1) {
243       FILE* f = tracing_files.at(this);
244       fclose(f);
245     }
246     tracing_files.erase(this);
247   } else {
248     THROW_IMPOSSIBLE;
249   }
250 }
251 }
252 }