dol: initial dol commit
[jump.git] / dol / src / dol / visitor / hds / lib / Performance_Extraction.cpp
1 #include "Performance_Extraction.h"
2 #include <string>
3 #include <fstream>
4
5
6 Performance_Extraction performance_extraction("static_characterization.xml");
7
8 /**
9  *
10  */
11 int get_current_time(CURRENT_TIME *current_time_ptr)
12 {
13     return clock_gettime(CLOCK_REALTIME, &(current_time_ptr->ts));
14 }
15
16
17 /**
18  *
19  */
20 double sub_time(CURRENT_TIME *start_time_ptr, CURRENT_TIME *end_time_ptr)
21 {
22     CURRENT_TIME diff_time;
23     double time_ns;
24
25     diff_time.ts.tv_sec = end_time_ptr->ts.tv_sec - start_time_ptr->ts.tv_sec;
26     diff_time.ts.tv_nsec = end_time_ptr->ts.tv_nsec - start_time_ptr->ts.tv_nsec;
27     time_ns = diff_time.ts.tv_sec * 1E+9 + diff_time.ts.tv_nsec;
28
29     return time_ns;
30 }
31
32
33 /**
34  *
35  */
36 Process_Performance::Process_Performance(const char *name)
37 {
38     strcpy(_process_name, name);
39     _head = NULL;
40     _tail = NULL;
41 }
42
43
44 /**
45  *
46  */
47 Process_Performance::~Process_Performance()
48 {
49     COMP_ENTRY *temp;
50     DBGPRINT;
51     while (_head != NULL) {
52         temp = _head;
53         _head = _head->next;
54         delete temp;
55     }
56 }
57
58
59 /**
60  *
61  */
62 const char *Process_Performance::get_name()
63 {
64     return _process_name;
65 }
66
67
68 /**
69  *
70  */
71 COMP_ENTRY *Process_Performance::get_head_entry()
72 {
73     return _head;
74 }
75
76
77 /**
78  *
79  */
80 COMP_ENTRY *Process_Performance::get_entry(int start_line, int end_line)
81 {
82     COMP_ENTRY *temp = NULL;
83     temp = _head;
84     while (temp != NULL) {
85         if ((temp->start_line == start_line) && (temp->end_line == end_line)) {
86             break;
87         }
88         temp = temp->next;
89     }
90
91     return temp;
92 }
93
94
95 /**
96  *
97  */
98 COMP_ENTRY *Process_Performance::add_entry(int start_line, int end_line)
99 {
100     COMP_ENTRY *temp = NULL;
101     temp = get_entry(start_line, end_line);
102     if (temp == NULL) {
103         temp = new COMP_ENTRY;
104
105         if (_head == NULL) {
106             _head = temp;
107             _tail = temp;
108             temp->next = NULL;
109         } else {
110             _tail->next = temp;
111             _tail = temp;
112             temp->next = NULL;
113         }
114         temp->start_line = start_line;
115         temp->end_line = end_line;
116         temp->total_computation_time = 0;
117         temp->called_times = 0;
118     }
119
120     return temp;
121 }
122
123
124 /**
125  *
126  */
127 int Process_Performance::set_entry(int start_line, int end_line,
128                                    CURRENT_TIME *start_time_ptr,
129                                    CURRENT_TIME *end_time_ptr)
130 {
131     int ret = 0;
132     COMP_ENTRY *temp;
133     double computation_time;
134     computation_time = sub_time(start_time_ptr, end_time_ptr);
135     temp = get_entry(start_line, end_line);
136     if (temp == NULL) {
137         temp = add_entry(start_line, end_line);
138     }
139
140     temp->total_computation_time += computation_time;
141     temp->called_times++;
142
143     return ret;
144 }
145
146
147 /**
148  *
149  */
150 Performance_Extraction::Performance_Extraction(const char *chr_file_name)
151 {
152     strcpy(_chr_file_name, chr_file_name);
153 }
154
155
156 /**
157  *
158  */
159 Performance_Extraction::~Performance_Extraction()
160 {
161     Process_Performance *process_performance_ptr;
162
163 #ifdef INCLUDE_PERFORMANCE
164     //strcpy(_processor_type, "DSP");
165     //add_to_xml_file(_chr_file_name);
166     //strcpy(_processor_type, "RISC");
167     //add_to_xml_file(_chr_file_name);
168
169     write_to_xml_file(_chr_file_name);
170 #endif
171
172     for (_iter_process_performance = _list_process_performance.begin();
173          _iter_process_performance != _list_process_performance.end();
174          _iter_process_performance++)
175     {
176         process_performance_ptr = *_iter_process_performance;
177         delete process_performance_ptr;
178     }
179     _list_process_performance.clear();
180
181 }
182
183
184 /**
185  *
186  */
187 int Performance_Extraction::add_computation_performance(
188     const char *process_name, int start_line, int end_line,
189     CURRENT_TIME *start_time_ptr, CURRENT_TIME *end_time_ptr)
190 {
191     int ret = 0;
192     Process_Performance *process_performance_ptr;
193
194     process_performance_ptr = get_process_performance(process_name);
195     if (process_performance_ptr == NULL) {
196         process_performance_ptr = new Process_Performance(process_name);
197         _list_process_performance.push_back(process_performance_ptr);
198     }
199
200     process_performance_ptr->set_entry(start_line, end_line,
201                                        start_time_ptr, end_time_ptr);
202
203     return ret;
204 }
205
206
207 /**
208  *
209  */
210 Process_Performance *Performance_Extraction::get_process_performance(
211     const char *process_name)
212 {
213     Process_Performance *process_performance_ptr = NULL;
214
215     for (_iter_process_performance = _list_process_performance.begin();
216          _iter_process_performance != _list_process_performance.end();
217          _iter_process_performance++) {
218         process_performance_ptr = *_iter_process_performance;
219         if (strcmp(process_performance_ptr->get_name(), process_name) == 0) {
220             break;
221         }
222     }
223
224     if (_iter_process_performance == _list_process_performance.end()) {
225         process_performance_ptr = NULL;
226     }
227
228     return process_performance_ptr;
229 }
230
231
232 /**
233  * write performance data into XML file. (identical to add_to_xml_file()
234  * if file does not exist).
235  */
236 int Performance_Extraction::write_to_xml_file(const char *chr_file_name)
237 {
238     char start_line_str[NAME_LENGTH];
239     char end_line_str[NAME_LENGTH];
240     char computation_time_str[NAME_LENGTH];
241     double computation_time;
242     Process_Performance *process_performance_ptr;
243     COMP_ENTRY *comp_entry;
244
245     //create xml
246     string text = "<?xml version=\"1.0\"?>\n<characterization>\n";
247     for (_iter_process_performance = _list_process_performance.begin();
248          _iter_process_performance != _list_process_performance.end();
249          _iter_process_performance++) {
250         process_performance_ptr = *_iter_process_performance;
251
252         text += "  <process name=\"";
253         text += process_performance_ptr->get_name();
254         text += "\">\n";
255
256         for (comp_entry = process_performance_ptr->get_head_entry();
257              comp_entry != NULL;
258              comp_entry = comp_entry->next) {
259             sprintf(start_line_str, "%d", comp_entry->start_line);
260             sprintf(end_line_str, "%d", comp_entry->end_line);
261
262             //hack to eliminate the overhead of system call clock_gettime.
263             //computation_time is nano sec. To get cycles, need to mutiply
264             //by the frequency of cpu. result is in cycles.
265             computation_time = (comp_entry->total_computation_time
266                                 / comp_entry->called_times - SYS_OVERHEAD)
267                                 * HOST_FREQUENCY;
268             if (computation_time < 0) {
269                 computation_time = 0;
270             }
271             sprintf(computation_time_str, "%.0f", computation_time);
272
273             text += "    <computation start=\"";
274             text += start_line_str;
275             text += "\" end=\"";
276             text += end_line_str;
277             text += "\">\n";
278             text += "      <processor type=\"DSP\" time=\"";
279             text += computation_time_str;
280             text += "\"/>\n";
281             text += "      <processor type=\"RISC\" time=\"";
282             text += computation_time_str;
283             text += "\"/>\n";
284             text += "    </computation>\n";
285         }
286         text += "  </process>\n";
287     }
288     text += "  <communication name=\"read\">\n";
289     text += "    <processor type=\"DSP\" time=\"2\"/>\n";
290     text += "    <processor type=\"RISC\" time=\"2\"/>\n";
291     text += "  </communication>\n";
292     text += "  <communication name=\"write\">\n";
293     text += "    <processor type=\"DSP\" time=\"2\"/>\n";
294     text += "    <processor type=\"RISC\" time=\"2\"/>\n";
295     text += "  </communication>\n";
296     text += "</characterization>\n";
297
298     //write xml to file
299     std::ofstream out(chr_file_name, ios::out);
300     if (!out) {
301       printf("Cannot open file %s. Return.\n", chr_file_name);
302       return -1;
303     }
304     out.write(text.c_str(), text.size());
305     out.close();
306     return 0;
307 }
308
309
310 /**
311  * add performance data to existing XML file (or create new one if file
312  * does not exist).
313  */
314 int Performance_Extraction::add_to_xml_file(const char *chr_file_name)
315 {
316     int ret = 0;
317     XMLNode file_node;
318     XMLNode root_node;
319     XMLNode process_node;
320     XMLNode comp_node;
321     int computation_index = 0;
322     XMLNode processor_node;
323     XMLNode read_node;
324     XMLNode write_node;
325
326     Process_Performance *process_performance_ptr;
327     COMP_ENTRY *comp_entry;
328
329     char start_line_str[NAME_LENGTH];
330     char end_line_str[NAME_LENGTH];
331     char computation_time_str[NAME_LENGTH];
332     double computation_time;
333
334     file_node = XMLNode::parseFile(chr_file_name);
335     if (file_node.isEmpty()) {
336         file_node = XMLNode::createXMLTopNode("xml", TRUE);
337         file_node.addAttribute("version", "1.0");
338         root_node = file_node.addChild("characterization");
339     }
340
341     root_node = file_node.getChildNode();
342     if (root_node.isEmpty()) {
343         ret = -1;
344         printf("Open characterization file error\n");
345         return ret;
346     }
347
348     for (_iter_process_performance = _list_process_performance.begin();
349          _iter_process_performance != _list_process_performance.end();
350          _iter_process_performance++) {
351         process_performance_ptr = *_iter_process_performance;
352
353         printf("%s\n", process_performance_ptr->get_name());
354
355         process_node = root_node.getChildNodeWithAttribute(
356             "process", "name", process_performance_ptr->get_name());
357         if (process_node.isEmpty())
358         {
359             process_node = root_node.addChild("process");
360             process_node.addAttribute(
361                 "name",process_performance_ptr->get_name());
362         }
363
364         for (comp_entry = process_performance_ptr->get_head_entry();
365              comp_entry != NULL;
366              comp_entry = comp_entry->next) {
367             sprintf(start_line_str, "%d", comp_entry->start_line);
368             sprintf(end_line_str, "%d", comp_entry->end_line);
369
370             printf("%d %d\n", comp_entry->start_line, comp_entry->end_line);
371
372             /* Hack to eliminate the overhead of system call clock_gettime.
373                computation_time is nano sec. To get cycles, need to mutiply
374                by the frequency of cpu.
375                result is cycles */
376             computation_time = (comp_entry->total_computation_time
377                                 / comp_entry->called_times - SYS_OVERHEAD)
378                                 * HOST_FREQUENCY;
379
380             if (computation_time < 0) {
381                 computation_time = 0;
382             }
383
384             sprintf(computation_time_str, "%.0f", computation_time);
385             computation_index = 0;
386             comp_node = process_node.getChildNode("computation",
387                                                   computation_index++);
388             while (!comp_node.isEmpty()) {
389                 if (strcmp(comp_node.getAttribute("start"),start_line_str)==0
390                     && strcmp(comp_node.getAttribute("end"),end_line_str)==0) {
391                     break;
392                 }
393
394                 comp_node = process_node.getChildNode("computation",
395                                                       computation_index++);
396             }
397
398             if (comp_node.isEmpty()) {
399                 comp_node = process_node.addChild("computation");
400                 comp_node.addAttribute("start", start_line_str);
401                 comp_node.addAttribute("end", end_line_str);
402             }
403
404             processor_node = comp_node.getChildNodeWithAttribute("processor", "type", _processor_type);
405             if (processor_node.isEmpty()) {
406                 processor_node = comp_node.addChild("processor");
407                 processor_node.addAttribute("type", _processor_type);
408                 processor_node.addAttribute("time", computation_time_str);
409             }
410         }
411     }
412
413     read_node = root_node.getChildNodeWithAttribute("communication",
414                                                     "name", "read");
415     if (read_node.isEmpty()) {
416         read_node = root_node.addChild("communication");
417         read_node.addAttribute("name", "read");
418     }
419
420     processor_node = read_node.getChildNodeWithAttribute("processor",
421                                                          "type",
422                                                          _processor_type);
423     if (processor_node.isEmpty()) {
424         processor_node = read_node.addChild("processor");
425         processor_node.addAttribute("type", _processor_type);
426         processor_node.addAttribute("time", "2");
427     }
428
429     write_node = root_node.getChildNodeWithAttribute("communication",
430                                                      "name", "write");
431     if (write_node.isEmpty()) {
432         write_node = root_node.addChild("communication");
433         write_node.addAttribute("name", "write");
434     }
435
436     processor_node = write_node.getChildNodeWithAttribute("processor",
437                                                           "type",
438                                                           _processor_type);
439     if (processor_node.isEmpty()) {
440         processor_node = write_node.addChild("processor");
441         processor_node.addAttribute("type", _processor_type);
442         processor_node.addAttribute("time", "2");
443     }
444
445     file_node.writeToFile(chr_file_name);
446     return 0;
447 }