4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
22 * Copyright (c) 2014 Gary Mills
23 * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
24 * Use is subject to license terms.
27 #include <sys/types.h>
33 * Support routines for CPR statistic collection
35 struct cpr_event cpr_events_buf
[CPR_E_MAX_EVENTNUM
];
37 extern struct cpr_terminator cpr_term
;
39 struct cpr_event
*cpr_find_event(char *name
, int new);
41 #define CPR_DEFAULT_PROMTIME 30
42 #define CE_START_MASK 0x8000000
45 * Use ctp to specify another time point instead of the current time;
46 * Otherwise, ctp is NULL.
49 cpr_stat_event_start(char *name
, cpr_time_t
*ctp
)
51 struct cpr_event
*cep
;
57 /* need relative time even when hrestime is stoped */
61 if ((cep
= cpr_find_event(name
, 1)) == NULL
) {
62 cpr_err(CE_WARN
, "cpr_stat: run out of event buffers");
66 * disallow entering start twice without calling end first
68 if (cep
->ce_ntests
& CE_START_MASK
)
71 cep
->ce_ntests
|= CE_START_MASK
;
72 cep
->ce_sec
.stime
= cep
->ce_sec
.etime
= tv
.tv_sec
;
73 cep
->ce_sec
.ltime
= 0;
74 cep
->ce_msec
.stime
= cep
->ce_msec
.etime
= tv
.tv_nsec
/ 100000000;
75 cep
->ce_msec
.ltime
= 0;
79 cpr_stat_event_end(char *name
, cpr_time_t
*ctp
)
81 struct cpr_stat
*cp
= STAT
;
82 struct cpr_event
*cep
;
90 if ((cep
= cpr_find_event(name
, 0)) == NULL
) {
92 prom_printf("cpr_stat: event \"%s\" is not monitored\n", name
);
98 * diallow entering end twice without calling end first
100 if (!(cep
->ce_ntests
& CE_START_MASK
))
103 cep
->ce_ntests
&= ~CE_START_MASK
;
109 cep
->ce_sec
.etime
= tv
.tv_sec
;
110 cep
->ce_sec
.ltime
= cep
->ce_sec
.etime
- cep
->ce_sec
.stime
;
111 cep
->ce_sec
.mtime
= ((cep
->ce_sec
.mtime
* (cep
->ce_ntests
- 1)) +
112 cep
->ce_sec
.ltime
) / cep
->ce_ntests
;
115 * calculate 100*milliseconds
117 if (cep
->ce_sec
.ltime
== 0) {
118 cep
->ce_msec
.etime
= tv
.tv_nsec
/ 100000000;
120 (cep
->ce_msec
.etime
<= cep
->ce_msec
.stime
) ? 0 :
121 (cep
->ce_msec
.etime
- cep
->ce_msec
.stime
);
123 ((cep
->ce_msec
.mtime
* (cep
->ce_ntests
- 1)) +
124 cep
->ce_msec
.ltime
) / cep
->ce_ntests
;
126 cp
->cs_ntests
= cep
->ce_ntests
& ~CE_START_MASK
;
132 struct cpr_stat
*cp
= STAT
;
133 struct cpr_event
*cep
;
135 for (cep
= cp
->cs_event_head
; cep
; cep
= cep
->ce_next
) {
136 if ((cep
->ce_ntests
& CE_START_MASK
) &&
137 strcmp(cep
->ce_name
, "POST CPR DELAY") != 0) {
138 cpr_stat_event_end(cep
->ce_name
, 0);
139 cep
->ce_ntests
&= ~CE_START_MASK
;
147 STAT
->cs_real_statefsz
= 0;
148 STAT
->cs_dumped_statefsz
= 0;
152 cpr_stat_record_events()
154 if (cpr_term
.real_statef_size
) {
157 STAT
->cs_real_statefsz
= cpr_term
.real_statef_size
;
158 cur_comprate
= ((longlong_t
)((longlong_t
)
159 STAT
->cs_nocomp_statefsz
*100)/
160 STAT
->cs_real_statefsz
);
161 if (STAT
->cs_min_comprate
== 0 ||
162 (STAT
->cs_min_comprate
> cur_comprate
))
163 STAT
->cs_min_comprate
= cur_comprate
;
168 cpr_stat_event_print()
170 struct cpr_stat
*cp
= STAT
;
171 struct cpr_event
*cep
;
176 printf("---------------\t\tCPR PERFORMANCE SUMMARY\t\t-------------\n");
177 printf("Events\t\t\tRepeat[times]\tMeantime[sec]\tLastEvnt[sec]\n");
179 for (cep
= cp
->cs_event_head
; cep
; cep
= cep
->ce_next
) {
180 len
= strlen(cep
->ce_name
);
187 if (strcmp(cep
->ce_name
, "Suspend Total") == 0 ||
188 strcmp(cep
->ce_name
, "Resume Total") == 0 ||
189 strcmp(cep
->ce_name
, "POST CPR DELAY") == 0 ||
190 strcmp(cep
->ce_name
, "WHOLE CYCLE") == 0)
191 fmt
= "%s%s%d\t\t%3d.%1d\t\t%3d.%1d\n";
193 fmt
= "%s%s%d\t\t %3d.%1d\t\t %3d.%1d\n";
194 printf(fmt
, cep
->ce_name
, tabs
, (int)cep
->ce_ntests
,
195 (int)cep
->ce_sec
.mtime
, (int)(cep
->ce_msec
.mtime
/ 10),
196 (int)cep
->ce_sec
.ltime
, (int)(cep
->ce_msec
.ltime
/ 10));
198 delay(drv_usectohz(10000)); /* otherwise the next line goes to prom */
200 * print the rest of the stat data
202 printf("\nMISCELLANEOUS STATISTICS INFORMATION (units in KBytes)\n\n");
203 printf("\tUser Pages w/o Swapspace:\t%8lu (%lu pages)\n",
204 cp
->cs_nosw_pages
*PAGESIZE
/1000, cp
->cs_nosw_pages
);
205 printf("\tTotal Upages Saved to Statefile:%8d (%d pages)\n",
206 cp
->cs_upage2statef
*PAGESIZE
/1000, cp
->cs_upage2statef
);
208 printf("\tAverage Cluster Size:\t\t%8d (%d.%1d%1d pages)\n\n",
209 cp
->cs_mclustsz
/1000, cp
->cs_mclustsz
/PAGESIZE
,
210 ((cp
->cs_mclustsz
%PAGESIZE
)*10/PAGESIZE
),
211 ((cp
->cs_mclustsz
%PAGESIZE
)*100/PAGESIZE
)%10);
212 printf("\tKernel Memory Size:\t\t%8lu\n", cp
->cs_nocomp_statefsz
/1000);
213 printf("\tEstimated Statefile Size:\t%8lu\n", cp
->cs_est_statefsz
/1000);
214 printf("\tActual Statefile Size:\t\t%8lu\n", cp
->cs_real_statefsz
/1000);
215 if (cp
->cs_real_statefsz
) {
216 int min
= cp
->cs_min_comprate
;
217 int new = ((longlong_t
)((longlong_t
)
218 cp
->cs_nocomp_statefsz
*100)/cp
->cs_real_statefsz
);
220 printf("\tCompression Ratio:\t\t%5d.%1d%1d (worst %d.%1d%1d)\n",
221 new/100, (new%100)/10, new%10,
222 min
/100, (min
%100)/10, min
%10);
227 cpr_find_event(char *name
, int new)
229 struct cpr_stat
*cp
= STAT
;
230 struct cpr_event
*cep
;
233 for (cep
= cp
->cs_event_head
; cep
; cep
= cep
->ce_next
) {
234 if (strcmp(name
, cep
->ce_name
) == 0)
238 /* if not begin not end either */
242 for (i
= 0; i
< CPR_E_MAX_EVENTNUM
; i
++) {
243 for (cep
= cp
->cs_event_head
; cep
; cep
= cep
->ce_next
) {
244 if (&cpr_events_buf
[i
] == cep
)
248 struct cpr_event
*new_cep
;
250 new_cep
= &cpr_events_buf
[i
];
251 (void) strcpy(new_cep
->ce_name
, name
);
253 if (!cp
->cs_event_head
) {
255 cp
->cs_event_head
= new_cep
;
258 new_cep
->ce_next
= cp
->cs_event_tail
->ce_next
;
259 cp
->cs_event_tail
->ce_next
= new_cep
;
261 cp
->cs_event_tail
= new_cep
;
268 static time_t min_promtime
;
271 cpr_convert_promtime(cpr_time_t
*pop
)
273 time_t pwroff_time
, cb_time
;
274 cpr_time_t
*startp
, *shdnp
, *endp
;
276 startp
= &cpr_term
.tm_cprboot_start
;
277 shdnp
= &cpr_term
.tm_shutdown
;
278 endp
= &cpr_term
.tm_cprboot_end
;
280 cb_time
= endp
->tv_sec
- startp
->tv_sec
;
283 startp
->tv_sec
= endp
->tv_sec
- cb_time
;
285 if (min_promtime
== 0 ||
286 min_promtime
> (endp
->tv_sec
- shdnp
->tv_sec
- cb_time
))
287 min_promtime
= endp
->tv_sec
- shdnp
->tv_sec
- cb_time
;
289 if (min_promtime
> CPR_DEFAULT_PROMTIME
)
290 min_promtime
= CPR_DEFAULT_PROMTIME
;
292 pwroff_time
= startp
->tv_sec
- shdnp
->tv_sec
- min_promtime
;
294 wholecycle_tv
.tv_sec
+= pwroff_time
; /* offset the poweroff time */
296 pop
->tv_sec
= startp
->tv_sec
- min_promtime
;