ysr@777: /* ysr@777: * Copyright 2001-2007 Sun Microsystems, Inc. All Rights Reserved. ysr@777: * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. ysr@777: * ysr@777: * This code is free software; you can redistribute it and/or modify it ysr@777: * under the terms of the GNU General Public License version 2 only, as ysr@777: * published by the Free Software Foundation. ysr@777: * ysr@777: * This code is distributed in the hope that it will be useful, but WITHOUT ysr@777: * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or ysr@777: * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License ysr@777: * version 2 for more details (a copy is included in the LICENSE file that ysr@777: * accompanied this code). ysr@777: * ysr@777: * You should have received a copy of the GNU General Public License version ysr@777: * 2 along with this work; if not, write to the Free Software Foundation, ysr@777: * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. ysr@777: * ysr@777: * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, ysr@777: * CA 95054 USA or visit www.sun.com if you need additional information or ysr@777: * have any questions. ysr@777: * ysr@777: */ ysr@777: ysr@777: // Keeps track of the GC overhead (both concurrent and STW). It stores ysr@777: // it in a large array and then prints it to tty at the end of the ysr@777: // execution. ysr@777: ysr@777: // See coTracker.hpp for the explanation on what groups are. ysr@777: ysr@777: // Let's set a maximum number of concurrent overhead groups, to ysr@777: // statically allocate any arrays we need and not to have to ysr@777: // malloc/free them. This is just a bit more convenient. ysr@777: enum { ysr@777: MaxGCOverheadGroupNum = 4 ysr@777: }; ysr@777: ysr@777: typedef struct { ysr@777: double _start_sec; ysr@777: double _end_sec; ysr@777: ysr@777: double _conc_overhead[MaxGCOverheadGroupNum]; ysr@777: double _stw_overhead; ysr@777: } GCOverheadReporterEntry; ysr@777: ysr@777: class GCOverheadReporter { ysr@777: friend class COReportingThread; ysr@777: ysr@777: private: ysr@777: enum PrivateConstants { ysr@777: DefaultReporterLength = 128 * 1024 ysr@777: }; ysr@777: ysr@777: // Reference to the single instance of this class. ysr@777: static GCOverheadReporter* _reporter; ysr@777: ysr@777: // These three references point to the array that contains the GC ysr@777: // overhead entries (_base is the base of the array, _top is the ysr@777: // address passed the last entry of the array, _curr is the next ysr@777: // entry to be used). ysr@777: GCOverheadReporterEntry* _base; ysr@777: GCOverheadReporterEntry* _top; ysr@777: GCOverheadReporterEntry* _curr; ysr@777: ysr@777: // The number of concurrent overhead groups. ysr@777: size_t _group_num; ysr@777: ysr@777: // The wall-clock time of the end of the last recorded period of GC ysr@777: // overhead. ysr@777: double _prev_end_sec; ysr@777: ysr@777: // Names for the concurrent overhead groups. ysr@777: const char* _group_names[MaxGCOverheadGroupNum]; ysr@777: ysr@777: // Add a new entry to the large array. conc_overhead being NULL is ysr@777: // equivalent to an array full of 0.0s. conc_overhead should have a ysr@777: // length of at least _group_num. ysr@777: void add(double start_sec, double end_sec, ysr@777: double* conc_overhead, ysr@777: double stw_overhead); ysr@777: ysr@777: // Add an entry that represents concurrent GC overhead. ysr@777: // conc_overhead must be at least of length _group_num. ysr@777: // conc_overhead being NULL is equivalent to an array full of 0.0s. ysr@777: void add_conc_overhead(double start_sec, double end_sec, ysr@777: double* conc_overhead) { ysr@777: add(start_sec, end_sec, conc_overhead, 0.0); ysr@777: } ysr@777: ysr@777: // Add an entry that represents STW GC overhead. ysr@777: void add_stw_overhead(double start_sec, double end_sec, ysr@777: double stw_overhead) { ysr@777: add(start_sec, end_sec, NULL, stw_overhead); ysr@777: } ysr@777: ysr@777: // It records the start of a STW pause (i.e. it records the ysr@777: // concurrent overhead up to that point) ysr@777: void record_stw_start(double start_sec); ysr@777: ysr@777: // It records the end of a STW pause (i.e. it records the overhead ysr@777: // associated with the pause and adjusts all the trackers to reflect ysr@777: // the pause) ysr@777: void record_stw_end(double end_sec); ysr@777: ysr@777: // It queries all the trackers of their concurrent overhead and ysr@777: // records it. ysr@777: void collect_and_record_conc_overhead(double end_sec); ysr@777: ysr@777: // It prints the contents of the GC overhead array ysr@777: void print() const; ysr@777: ysr@777: ysr@777: // Constructor. The same preconditions for group_num and group_names ysr@777: // from initGCOverheadReporter apply here too. ysr@777: GCOverheadReporter(size_t group_num, ysr@777: const char* group_names[], ysr@777: size_t length = DefaultReporterLength); ysr@777: ysr@777: public: ysr@777: ysr@777: // statics ysr@777: ysr@777: // It initialises the GCOverheadReporter and launches the concurrent ysr@777: // overhead reporting thread. Both actions happen only if the ysr@777: // GCOverheadReporting parameter is set. The length of the ysr@777: // group_names array should be >= group_num and group_num should be ysr@777: // <= MaxGCOverheadGroupNum. Entries group_namnes[0..group_num-1] ysr@777: // should not be NULL. ysr@777: static void initGCOverheadReporter(size_t group_num, ysr@777: const char* group_names[]); ysr@777: ysr@777: // The following three are provided for convenience and they are ysr@777: // wrappers around record_stw_start(start_sec), record_stw_end(end_sec), ysr@777: // and print(). Each of these checks whether GC overhead reporting ysr@777: // is on (i.e. _reporter != NULL) and, if it is, calls the ysr@777: // corresponding method. Saves from repeating this pattern again and ysr@777: // again from the places where they need to be called. ysr@777: static void recordSTWStart(double start_sec); ysr@777: static void recordSTWEnd(double end_sec); ysr@777: static void printGCOverhead(); ysr@777: };