1 /******************************************************************************* 2 3 Contains API to obtain garbage collector stats. 4 5 Copyright: 6 Copyright (c) 2009-2018 dunnhumby Germany GmbH. 7 All rights reserved. 8 9 License: 10 Boost Software License Version 1.0. See LICENSE_BOOST.txt for details. 11 Alternatively, this file may be distributed under the terms of the Tango 12 3-Clause BSD License (see LICENSE_BSD.txt for details). 13 14 *******************************************************************************/ 15 16 module ocean.application.components.GCStats; 17 18 import core.memory; 19 20 import ocean.meta.traits.Aggregates : hasMember; 21 import ocean.meta.types.Function : ParametersOf; 22 import ocean.time.MicrosecondsClock; 23 24 /******************************************************************************* 25 26 Class used for getting used GC stats for the current process. This will 27 work only with dmd-transitional. 28 29 *******************************************************************************/ 30 31 public class GCStats 32 { 33 static if ( hasMember!(GC, "monitor") ) 34 { 35 /// The type of the gcEnd delegate 36 private alias ParametersOf!(GC.monitor)[1] MonitorEndParams; 37 38 /// Integers used by the gcEnd delegate 39 private alias ParametersOf!(MonitorEndParams)[0] MonitorInt; 40 } 41 else 42 { 43 pragma(msg, "There will be no gc stats! You need to use dmd transitional:"); 44 pragma(msg, "https://github.com/sociomantic-tsunami/dmd-transitional"); 45 46 /// Default type for integers used by monitor 47 private alias long MonitorInt; 48 } 49 50 /********************************************************************** 51 52 Structure representing recorded GC stats. 53 54 **********************************************************************/ 55 56 public struct Stats 57 { 58 /********************************************************************** 59 60 The number of microseconds the garbage collector ran for in the 61 last stats collection. 62 63 **********************************************************************/ 64 65 public size_t gc_run_duration; 66 67 /********************************************************************** 68 69 The percentage of time that was spent by the garbage collector in 70 the last stats collection. 71 72 **********************************************************************/ 73 74 public float gc_run_percentage = 0; 75 } 76 77 /// ditto 78 private Stats stats; 79 80 /// Timestamp for when the last garbage collection started 81 private ulong gc_start_us; 82 83 /********************************************************************** 84 85 Timestamp for when the last stats were collected used to 86 calculate the percentage of the time spent in GC between stats 87 cycles. 88 89 **********************************************************************/ 90 91 private ulong last_collected_timestamp; 92 93 /********************************************************************** 94 95 Reset statistics. 96 97 **********************************************************************/ 98 99 private void reset ( ) 100 { 101 this.last_collected_timestamp = MicrosecondsClock.now_us(); 102 this.stats.gc_run_duration = 0; 103 } 104 105 /********************************************************************** 106 107 Start stats reporting 108 109 **********************************************************************/ 110 111 public void start ( ) 112 { 113 static if ( hasMember!(GC, "monitor") ) 114 { 115 GC.monitor(&this.gcBegin, &this.gcEnd); 116 } 117 } 118 119 /********************************************************************** 120 121 Stop stats reporting 122 123 **********************************************************************/ 124 125 public void stop ( ) 126 { 127 static if ( hasMember!(GC, "monitor") ) 128 { 129 GC.monitor(null, null); 130 } 131 } 132 133 /*************************************************************************** 134 135 Get's the GC stats for the current process. 136 137 Returns: 138 Stats instance recording the current stats. 139 140 ***************************************************************************/ 141 142 public Stats collect () 143 { 144 auto result = this.stats; 145 this.reset(); 146 147 return result; 148 } 149 150 /********************************************************************** 151 152 Called each time the GC starts a collection 153 154 **********************************************************************/ 155 156 private void gcBegin ( ) 157 { 158 this.gc_start_us = MicrosecondsClock.now_us(); 159 } 160 161 /*************************************************************************** 162 163 Called when the GC completes a collection. 164 165 Params: 166 freed = the number of bytes freed overall 167 pagebytes = the number of bytes freed within full pages. 168 169 ***************************************************************************/ 170 171 private void gcEnd ( MonitorInt freed, MonitorInt pagebytes ) 172 { 173 auto now = MicrosecondsClock.now_us(); 174 175 this.stats.gc_run_duration += now - this.gc_start_us; 176 this.stats.gc_run_percentage = cast(float)this.stats.gc_run_duration / 177 cast(float)(now - last_collected_timestamp); 178 } 179 }