Mercurial > hg > CbC > CbC_gcc
comparison gcc/optinfo-emit-json.cc @ 145:1830386684a0
gcc-9.2.0
author | anatofuz |
---|---|
date | Thu, 13 Feb 2020 11:34:05 +0900 |
parents | 84e7813d76e9 |
children |
comparison
equal
deleted
inserted
replaced
131:84e7813d76e9 | 145:1830386684a0 |
---|---|
1 /* Emit optimization information as JSON files. | 1 /* Emit optimization information as JSON files. |
2 Copyright (C) 2018 Free Software Foundation, Inc. | 2 Copyright (C) 2018-2020 Free Software Foundation, Inc. |
3 Contributed by David Malcolm <dmalcolm@redhat.com>. | 3 Contributed by David Malcolm <dmalcolm@redhat.com>. |
4 | 4 |
5 This file is part of GCC. | 5 This file is part of GCC. |
6 | 6 |
7 GCC is free software; you can redistribute it and/or modify it under | 7 GCC is free software; you can redistribute it and/or modify it under |
43 #include "version.h" | 43 #include "version.h" |
44 #include "context.h" | 44 #include "context.h" |
45 #include "pass_manager.h" | 45 #include "pass_manager.h" |
46 #include "selftest.h" | 46 #include "selftest.h" |
47 #include "dump-context.h" | 47 #include "dump-context.h" |
48 | 48 #include <zlib.h> |
49 /* A class for writing out optimization records in JSON format. */ | |
50 | |
51 class optrecord_json_writer | |
52 { | |
53 public: | |
54 optrecord_json_writer (); | |
55 ~optrecord_json_writer (); | |
56 void write () const; | |
57 void add_record (const optinfo *optinfo); | |
58 void pop_scope (); | |
59 | |
60 void add_record (json::object *obj); | |
61 json::object *impl_location_to_json (dump_impl_location_t loc); | |
62 json::object *location_to_json (location_t loc); | |
63 json::object *profile_count_to_json (profile_count count); | |
64 json::string *get_id_value_for_pass (opt_pass *pass); | |
65 json::object *pass_to_json (opt_pass *pass); | |
66 json::value *inlining_chain_to_json (location_t loc); | |
67 json::object *optinfo_to_json (const optinfo *optinfo); | |
68 void add_pass_list (json::array *arr, opt_pass *pass); | |
69 | |
70 private: | |
71 /* The root value for the JSON file. | |
72 Currently the JSON values are stored in memory, and flushed when the | |
73 compiler exits. It would probably be better to simply write out | |
74 the JSON as we go. */ | |
75 json::array *m_root_tuple; | |
76 | |
77 /* The currently open scopes, for expressing nested optimization records. */ | |
78 auto_vec<json::array *> m_scopes; | |
79 }; | |
80 | 49 |
81 /* optrecord_json_writer's ctor. Populate the top-level parts of the | 50 /* optrecord_json_writer's ctor. Populate the top-level parts of the |
82 in-memory JSON representation. */ | 51 in-memory JSON representation. */ |
83 | 52 |
84 optrecord_json_writer::optrecord_json_writer () | 53 optrecord_json_writer::optrecord_json_writer () |
131 /* Choose an appropriate filename, and write the saved records to it. */ | 100 /* Choose an appropriate filename, and write the saved records to it. */ |
132 | 101 |
133 void | 102 void |
134 optrecord_json_writer::write () const | 103 optrecord_json_writer::write () const |
135 { | 104 { |
136 char *filename = concat (dump_base_name, ".opt-record.json", NULL); | 105 pretty_printer pp; |
137 FILE *outfile = fopen (filename, "w"); | 106 m_root_tuple->print (&pp); |
107 | |
108 bool emitted_error = false; | |
109 char *filename = concat (dump_base_name, ".opt-record.json.gz", NULL); | |
110 gzFile outfile = gzopen (filename, "w"); | |
111 if (outfile == NULL) | |
112 { | |
113 error_at (UNKNOWN_LOCATION, "cannot open file %qs for writing optimization records", | |
114 filename); // FIXME: more info? | |
115 goto cleanup; | |
116 } | |
117 | |
118 if (gzputs (outfile, pp_formatted_text (&pp)) <= 0) | |
119 { | |
120 int tmp; | |
121 error_at (UNKNOWN_LOCATION, "error writing optimization records to %qs: %s", | |
122 filename, gzerror (outfile, &tmp)); | |
123 emitted_error = true; | |
124 } | |
125 | |
126 cleanup: | |
138 if (outfile) | 127 if (outfile) |
139 { | 128 if (gzclose (outfile) != Z_OK) |
140 m_root_tuple->dump (outfile); | 129 if (!emitted_error) |
141 fclose (outfile); | 130 error_at (UNKNOWN_LOCATION, "error closing optimization records %qs", |
142 } | 131 filename); |
143 else | 132 |
144 error_at (UNKNOWN_LOCATION, "unable to write optimization records to %qs", | |
145 filename); // FIXME: more info? | |
146 free (filename); | 133 free (filename); |
147 } | 134 } |
148 | 135 |
149 /* Add a record for OPTINFO to the queue of records to be written. */ | 136 /* Add a record for OPTINFO to the queue of records to be written. */ |
150 | 137 |
180 | 167 |
181 void | 168 void |
182 optrecord_json_writer::pop_scope () | 169 optrecord_json_writer::pop_scope () |
183 { | 170 { |
184 m_scopes.pop (); | 171 m_scopes.pop (); |
172 | |
173 /* We should never pop the top-level records array. */ | |
174 gcc_assert (m_scopes.length () > 0); | |
185 } | 175 } |
186 | 176 |
187 /* Create a JSON object representing LOC. */ | 177 /* Create a JSON object representing LOC. */ |
188 | 178 |
189 json::object * | 179 json::object * |
190 optrecord_json_writer::impl_location_to_json (dump_impl_location_t loc) | 180 optrecord_json_writer::impl_location_to_json (dump_impl_location_t loc) |
191 { | 181 { |
192 json::object *obj = new json::object (); | 182 json::object *obj = new json::object (); |
193 obj->set ("file", new json::string (loc.m_file)); | 183 obj->set ("file", new json::string (loc.m_file)); |
194 obj->set ("line", new json::number (loc.m_line)); | 184 obj->set ("line", new json::integer_number (loc.m_line)); |
195 if (loc.m_function) | 185 if (loc.m_function) |
196 obj->set ("function", new json::string (loc.m_function)); | 186 obj->set ("function", new json::string (loc.m_function)); |
197 return obj; | 187 return obj; |
198 } | 188 } |
199 | 189 |
204 { | 194 { |
205 gcc_assert (LOCATION_LOCUS (loc) != UNKNOWN_LOCATION); | 195 gcc_assert (LOCATION_LOCUS (loc) != UNKNOWN_LOCATION); |
206 expanded_location exploc = expand_location (loc); | 196 expanded_location exploc = expand_location (loc); |
207 json::object *obj = new json::object (); | 197 json::object *obj = new json::object (); |
208 obj->set ("file", new json::string (exploc.file)); | 198 obj->set ("file", new json::string (exploc.file)); |
209 obj->set ("line", new json::number (exploc.line)); | 199 obj->set ("line", new json::integer_number (exploc.line)); |
210 obj->set ("column", new json::number (exploc.column)); | 200 obj->set ("column", new json::integer_number (exploc.column)); |
211 return obj; | 201 return obj; |
212 } | 202 } |
213 | 203 |
214 /* Create a JSON object representing COUNT. */ | 204 /* Create a JSON object representing COUNT. */ |
215 | 205 |
216 json::object * | 206 json::object * |
217 optrecord_json_writer::profile_count_to_json (profile_count count) | 207 optrecord_json_writer::profile_count_to_json (profile_count count) |
218 { | 208 { |
219 json::object *obj = new json::object (); | 209 json::object *obj = new json::object (); |
220 obj->set ("value", new json::number (count.to_gcov_type ())); | 210 obj->set ("value", new json::integer_number (count.to_gcov_type ())); |
221 obj->set ("quality", | 211 obj->set ("quality", |
222 new json::string (profile_quality_as_string (count.quality ()))); | 212 new json::string (profile_quality_as_string (count.quality ()))); |
223 return obj; | 213 return obj; |
224 } | 214 } |
225 | 215 |
270 optgroup->name != NULL; optgroup++) | 260 optgroup->name != NULL; optgroup++) |
271 if (optgroup->value != OPTGROUP_ALL | 261 if (optgroup->value != OPTGROUP_ALL |
272 && (pass->optinfo_flags & optgroup->value)) | 262 && (pass->optinfo_flags & optgroup->value)) |
273 optgroups->append (new json::string (optgroup->name)); | 263 optgroups->append (new json::string (optgroup->name)); |
274 } | 264 } |
275 obj->set ("num", new json::number (pass->static_pass_number)); | 265 obj->set ("num", new json::integer_number (pass->static_pass_number)); |
276 return obj; | 266 return obj; |
277 } | 267 } |
278 | 268 |
279 /* Create a JSON array for LOC representing the chain of inlining | 269 /* Create a JSON array for LOC representing the chain of inlining |
280 locations. | 270 locations. |
419 obj->set ("location", location_to_json (loc)); | 409 obj->set ("location", location_to_json (loc)); |
420 } | 410 } |
421 | 411 |
422 if (current_function_decl) | 412 if (current_function_decl) |
423 { | 413 { |
424 const char *fnname = get_fnname_from_decl (current_function_decl); | 414 const char *fnname |
415 = IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (current_function_decl)); | |
425 obj->set ("function", new json::string (fnname)); | 416 obj->set ("function", new json::string (fnname)); |
426 } | 417 } |
427 | 418 |
428 if (loc != UNKNOWN_LOCATION) | 419 if (loc != UNKNOWN_LOCATION) |
429 obj->set ("inlining_chain", inlining_chain_to_json (loc)); | 420 obj->set ("inlining_chain", inlining_chain_to_json (loc)); |
450 pass = pass->next; | 441 pass = pass->next; |
451 } | 442 } |
452 while (pass); | 443 while (pass); |
453 } | 444 } |
454 | 445 |
455 /* File-level interface to rest of compiler (to avoid exposing | |
456 class optrecord_json_writer outside of this file). */ | |
457 | |
458 static optrecord_json_writer *the_json_writer; | |
459 | |
460 /* Perform startup activity for -fsave-optimization-record. */ | |
461 | |
462 void | |
463 optimization_records_start () | |
464 { | |
465 /* Bail if recording not enabled. */ | |
466 if (!flag_save_optimization_record) | |
467 return; | |
468 | |
469 the_json_writer = new optrecord_json_writer (); | |
470 } | |
471 | |
472 /* Perform cleanup activity for -fsave-optimization-record. | |
473 | |
474 Currently, the file is written out here in one go, before cleaning | |
475 up. */ | |
476 | |
477 void | |
478 optimization_records_finish () | |
479 { | |
480 /* Bail if recording not enabled. */ | |
481 if (!the_json_writer) | |
482 return; | |
483 | |
484 the_json_writer->write (); | |
485 | |
486 delete the_json_writer; | |
487 the_json_writer = NULL; | |
488 } | |
489 | |
490 /* Did the user request optimization records to be written out? */ | |
491 | |
492 bool | |
493 optimization_records_enabled_p () | |
494 { | |
495 return the_json_writer != NULL; | |
496 } | |
497 | |
498 /* If optimization records were requested, then add a record for OPTINFO | |
499 to the queue of records to be written. */ | |
500 | |
501 void | |
502 optimization_records_maybe_record_optinfo (const optinfo *optinfo) | |
503 { | |
504 /* Bail if recording not enabled. */ | |
505 if (!the_json_writer) | |
506 return; | |
507 | |
508 the_json_writer->add_record (optinfo); | |
509 } | |
510 | |
511 /* Handling for the end of a dump scope for the | |
512 optimization records sink. */ | |
513 | |
514 void | |
515 optimization_records_maybe_pop_dump_scope () | |
516 { | |
517 /* Bail if recording not enabled. */ | |
518 if (!the_json_writer) | |
519 return; | |
520 | |
521 the_json_writer->pop_scope (); | |
522 } | |
523 | |
524 #if CHECKING_P | 446 #if CHECKING_P |
525 | 447 |
526 namespace selftest { | 448 namespace selftest { |
527 | 449 |
528 /* Verify that we can build a JSON optimization record from dump_* | 450 /* Verify that we can build a JSON optimization record from dump_* |
530 | 452 |
531 static void | 453 static void |
532 test_building_json_from_dump_calls () | 454 test_building_json_from_dump_calls () |
533 { | 455 { |
534 temp_dump_context tmp (true, true, MSG_NOTE); | 456 temp_dump_context tmp (true, true, MSG_NOTE); |
535 dump_location_t loc; | 457 dump_user_location_t loc; |
536 dump_printf_loc (MSG_NOTE, loc, "test of tree: "); | 458 dump_printf_loc (MSG_NOTE, loc, "test of tree: "); |
537 dump_generic_expr (MSG_NOTE, TDF_SLIM, integer_zero_node); | 459 dump_generic_expr (MSG_NOTE, TDF_SLIM, integer_zero_node); |
538 optinfo *info = tmp.get_pending_optinfo (); | 460 optinfo *info = tmp.get_pending_optinfo (); |
539 ASSERT_TRUE (info != NULL); | 461 ASSERT_TRUE (info != NULL); |
540 ASSERT_EQ (info->num_items (), 2); | 462 ASSERT_EQ (info->num_items (), 2); |