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]
23 * Copyright (c) 2003, 2010, Oracle and/or its affiliates. All rights reserved.
26 #include <sys/types.h>
40 #include "rcapd_stat.h"
41 #include "statcommon.h"
43 static char mode
[RC_MODE_LEN
];
44 static rcapd_stat_hdr_t hdr
;
46 static int unformatted
;
47 static time_t stat_mod
= 0;
49 static uint_t timestamp_fmt
= NODATE
;
53 char col_name
[LC_NAME_LEN
];
57 uint64_t col_rsslimit
;
58 uint64_t col_paged_eff
;
59 uint64_t col_paged_eff_old
;
60 uint64_t col_paged_eff_avg
;
61 uint64_t col_paged_att
;
62 uint64_t col_paged_att_old
;
63 uint64_t col_paged_att_avg
;
68 lcollection_stat_t col_src_stat
;
69 lcollection_stat_t col_old_stat
;
72 static col_t
*col_head
;
79 for (col
= col_head
; col
!= NULL
; col
= col
->col_next
)
80 if (col
->col_id
.rcid_type
== id
.rcid_type
&&
81 col
->col_id
.rcid_val
== id
.rcid_val
)
91 new_col
= malloc(sizeof (col_t
));
92 if (new_col
== NULL
) {
93 (void) fprintf(stderr
, gettext("rcapstat: malloc() failed\n"));
96 (void) memset(new_col
, 0, sizeof (col_t
));
97 new_col
->col_next
= col_head
;
100 col_head
->col_prev
= new_col
;
107 col_remove(col_t
*col
)
109 if (col
->col_prev
!= NULL
)
110 col
->col_prev
->col_next
= col
->col_next
;
111 if (col
->col_next
!= NULL
)
112 col
->col_next
->col_prev
= col
->col_prev
;
114 col_head
= col
->col_next
;
122 (void) fprintf(stderr
,
123 gettext("usage: rcapstat [-g] [-p | -z] [-T d|u] "
124 "[interval [count]]\n"));
129 format_size(char *str
, uint64_t size
, int length
)
133 size
= (size
+ 512) / 1024;
136 size
= (size
+ 512) / 1024;
140 (void) snprintf(str
, length
, "%4lld%c", size
, tag
);
144 read_stats(rcid_type_t stat_type
)
150 col_t
*col
, *col_next
;
151 lcollection_report_t report
;
154 if ((fd
= open(STAT_FILE_DEFAULT
, O_RDONLY
)) < 0) {
155 warn(gettext("rcapd is not active\n"));
159 if (fstat(fd
, &st
) == 0)
160 stat_mod
= st
.st_mtime
;
162 if (read(fd
, &hdr
, sizeof (hdr
)) != sizeof (hdr
)) {
163 (void) fprintf(stderr
,
164 gettext("rcapstat: can't read stat file header: %s\n"),
171 * Check if rcapd is running
174 (void) snprintf(procfile
, 20, "/proc/%lld/psinfo", pid
);
175 if ((proc_fd
= open(procfile
, O_RDONLY
)) < 0) {
176 warn(gettext("rcapd is not active\n"));
180 (void) close(proc_fd
);
182 (void) strncpy(mode
, hdr
.rs_mode
, RC_MODE_LEN
);
183 for (col
= col_head
; col
!= NULL
; col
= col
->col_next
) {
185 col
->col_paged_eff
= 0;
186 col
->col_paged_att
= 0;
189 while (read(fd
, &report
, sizeof (report
)) == sizeof (report
)) {
190 if (report
.lcol_id
.rcid_type
!= stat_type
)
193 col
= col_find(report
.lcol_id
);
195 col
= col_insert(report
.lcol_id
);
196 col
->col_paged_eff_old
= col
->col_paged_eff
=
197 report
.lcol_stat
.lcols_pg_eff
;
198 col
->col_paged_att_old
= col
->col_paged_att
=
199 report
.lcol_stat
.lcols_pg_att
;
202 (void) strncpy(col
->col_name
, report
.lcol_name
, LC_NAME_LEN
);
203 col
->col_vmsize
= report
.lcol_image_size
;
204 col
->col_rsssize
= report
.lcol_rss
;
205 col
->col_rsslimit
= report
.lcol_rss_cap
;
207 if (report
.lcol_stat
.lcols_pg_eff
> col
->col_paged_eff_old
) {
209 report
.lcol_stat
.lcols_pg_eff
-
210 col
->col_paged_eff_old
;
211 if (report
.lcol_stat
.lcols_scan_count
> col
->col_count
)
212 col
->col_paged_eff_avg
=
214 (report
.lcol_stat
.lcols_scan_count
-
217 col
->col_paged_eff_avg
= 0;
219 if (report
.lcol_stat
.lcols_pg_att
> col
->col_paged_att_old
) {
221 report
.lcol_stat
.lcols_pg_att
-
222 col
->col_paged_att_old
;
223 if (report
.lcol_stat
.lcols_scan_count
> col
->col_count
)
224 col
->col_paged_att_avg
=
226 (report
.lcol_stat
.lcols_scan_count
-
229 col
->col_paged_att_avg
= 0;
231 col
->col_paged_eff_old
= report
.lcol_stat
.lcols_pg_eff
;
232 col
->col_paged_att_old
= report
.lcol_stat
.lcols_pg_att
;
234 report
.lcol_stat
.lcols_proc_in
-
235 report
.lcol_stat
.lcols_proc_out
;
236 col
->col_count
= report
.lcol_stat
.lcols_scan_count
;
237 col
->col_src_stat
= report
.lcol_stat
;
244 while (col
!= NULL
) {
245 col_next
= col
->col_next
;
246 if (col
->col_fresh
== 0)
255 * Print each collection's interval statistics.
259 print_unformatted_stats(void)
263 #define DELTA(field) \
264 (col->col_src_stat.field - col->col_old_stat.field)
267 while (col
!= NULL
) {
268 if (bcmp(&col
->col_src_stat
, &col
->col_old_stat
,
269 sizeof (col
->col_src_stat
)) == 0) {
273 (void) printf("%s %s status: succeeded/attempted (k): "
274 "%llu/%llu, ineffective/scans/unenforced/samplings: "
275 "%llu/%llu/%llu/%llu, RSS min/max (k): %llu/%llu, cap %llu "
276 "kB, processes/thpt: %llu/%llu, %llu scans over %lld ms\n",
277 mode
, col
->col_name
, DELTA(lcols_pg_eff
),
278 DELTA(lcols_pg_att
), DELTA(lcols_scan_ineffective
),
279 DELTA(lcols_scan
), DELTA(lcols_unenforced_cap
),
280 DELTA(lcols_rss_sample
), col
->col_src_stat
.lcols_min_rss
,
281 col
->col_src_stat
.lcols_max_rss
, col
->col_rsslimit
,
282 (col
->col_src_stat
.lcols_proc_in
-
283 col
->col_old_stat
.lcols_proc_out
), DELTA(lcols_proc_out
),
284 DELTA(lcols_scan_count
),
285 NSEC2MSEC(DELTA(lcols_scan_time_complete
)));
286 col
->col_old_stat
= col
->col_src_stat
;
292 (void) printf(gettext("physical memory utilization: %3u%% "
293 "cap enforcement threshold: %3u%%\n"), hdr
.rs_pressure_cur
,
294 hdr
.rs_pressure_cap
);
299 print_stats(rcid_type_t stat_type
)
308 char paged_att_avg
[6];
309 char paged_eff_avg
[6];
310 static int count
= 0;
313 * Print a header once every 20 times if we're only displaying reports
314 * for one collection (10 times if -g is used). Print a header every
315 * interval otherwise.
317 if (count
== 0 || ncol
!= 1)
318 (void) printf("%6s %-15s %5s %5s %5s %5s %5s %5s %5s %5s\n",
319 "id", (stat_type
== RCIDT_PROJECT
? "project" : "zone"),
320 "nproc", "vm", "rss", "cap",
321 "at", "avgat", "pg", "avgpg");
322 if (++count
>= 20 || (count
>= 10 && global
!= 0) || ncol
!= 1)
325 for (col
= col_head
; col
!= NULL
; col
= col
->col_next
) {
326 if (col
->col_id
.rcid_type
!= stat_type
)
329 if (col
->col_paged_att
== 0)
330 (void) strlcpy(nproc
, "-", sizeof (nproc
));
332 (void) snprintf(nproc
, sizeof (nproc
), "%lld",
334 format_size(size
, col
->col_vmsize
, 6);
335 format_size(rss
, col
->col_rsssize
, 6);
336 format_size(limit
, col
->col_rsslimit
, 6);
337 format_size(paged_att
, col
->col_paged_att
, 6);
338 format_size(paged_eff
, col
->col_paged_eff
, 6);
339 format_size(paged_att_avg
, col
->col_paged_att_avg
, 6);
340 format_size(paged_eff_avg
, col
->col_paged_eff_avg
, 6);
341 (void) printf("%6lld %-15s %5s %5s %5s %5s %5s %5s %5s %5s\n",
342 col
->col_id
.rcid_val
, col
->col_name
,
345 paged_att
, paged_att_avg
,
346 paged_eff
, paged_eff_avg
);
349 (void) printf(gettext("physical memory utilization: %3u%% "
350 "cap enforcement threshold: %3u%%\n"), hdr
.rs_pressure_cur
,
351 hdr
.rs_pressure_cap
);
355 main(int argc
, char *argv
[])
363 /* project reporting is the default if no option is specified */
364 rcid_type_t stat_type
= RCIDT_PROJECT
;
366 (void) setlocale(LC_ALL
, "");
367 (void) textdomain(TEXT_DOMAIN
);
368 (void) setpname("rcapstat");
370 global
= unformatted
= 0;
371 while ((opt
= getopt(argc
, argv
, "gpuzT:")) != (int)EOF
) {
378 stat_type
= RCIDT_PROJECT
;
384 stat_type
= RCIDT_ZONE
;
390 timestamp_fmt
= UDATE
;
391 else if (*optarg
== 'd')
392 timestamp_fmt
= DDATE
;
405 if ((interval
= xatoi(argv
[optind
++])) <= 0)
406 die(gettext("invalid interval specified\n"));
408 if ((count
= xatoi(argv
[optind
++])) <= 0)
409 die(gettext("invalid count specified\n"));
412 if (argc
> optind
|| (projects
> 0 && zones
> 0))
415 while (always
|| count
-- > 0) {
416 if (read_stats(stat_type
) != E_SUCCESS
)
418 if (timestamp_fmt
!= NODATE
)
419 print_timestamp(timestamp_fmt
);
421 print_stats(stat_type
);
422 (void) fflush(stdout
);
424 (void) sleep(interval
);
428 print_unformatted_stats();
429 (void) fflush(stdout
);
430 while (stat(STAT_FILE_DEFAULT
, &st
) == 0 &&
431 st
.st_mtime
== stat_mod
)
432 (void) usleep((useconds_t
)(0.2 * MICROSEC
));