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);