]>
git.saurik.com Git - apple/system_cmds.git/blob - ltop.tproj/ltop.c
9 #include <sys/sysctl.h>
10 #include <Kernel/kern/ledger.h>
11 #include <mach/mach_types.h>
13 extern int ledger(int cmd
, caddr_t arg1
, caddr_t arg2
, caddr_t arg3
);
16 char *group_print
= NULL
;
17 char *resource_print
= NULL
;
23 char name
[2 * MAXCOMLEN
];
24 struct ledger
*ledger
;
25 struct proc_list
*next
;
28 struct proc_list
*procs
= NULL
;
29 struct ledger_template_info
*template = NULL
;
36 struct ledger_entry_info
*info
;
37 struct ledger_entry_info
*old_info
;
41 struct ledger
*ledgers
= NULL
;
44 get_template_info(void)
51 /* Allocate enough space to accomodate a few new entries */
53 buf
= malloc(cnt
* sizeof (struct ledger_template_info
));
55 fprintf(stderr
, "Out of memory\n");
59 if (ledger(LEDGER_TEMPLATE_INFO
, (caddr_t
)buf
, (caddr_t
)&cnt
, NULL
) < 0) {
60 perror("ledger() system call failed");
64 /* We underestimated how many entries we needed. Let's try again */
65 if (cnt
== entry_cnt
+ 5) {
75 * Note - this is a destructive operation. Unless we're about to exit, this
76 * needs to be followed by another call to get_template_info().
79 dump_template_info(void)
82 const char *group
= NULL
;
84 printf("Resources being tracked:\n");
85 printf("\t%10s %15s %8s\n", "GROUP", "RESOURCE", "UNITS");
86 for (i
= 0; i
< entry_cnt
; i
++) {
87 if (strlen(template[i
].lti_name
) == 0)
90 group
= template[i
].lti_group
;
91 for (j
= i
; j
< entry_cnt
; j
++) {
92 if (strcmp(template[j
].lti_group
, group
))
94 printf("\t%10s %15s %8s\n", template[j
].lti_group
,
95 template[j
].lti_name
, template[j
].lti_units
);
96 template[j
].lti_name
[0] = '\0';
106 if (template == NULL
)
109 for (i
= 0; i
< entry_cnt
; i
++)
110 if (!strcmp(group_print
, template[i
].lti_group
))
113 fprintf(stderr
, "No such group: %s\n", group_print
);
118 validate_resource(void)
122 if (template == NULL
)
125 for (i
= 0; i
< entry_cnt
; i
++)
126 if (!strcmp(resource_print
, template[i
].lti_name
))
129 fprintf(stderr
, "No such resource: %s\n", resource_print
);
134 get_kern_max_proc(void)
136 int mib
[] = { CTL_KERN
, KERN_MAXPROC
};
138 size_t max_sz
= sizeof (max
);
140 if (sysctl(mib
, 2, &max
, &max_sz
, NULL
, 0) < 0) {
141 perror("Failed to get max proc count");
148 static struct ledger
*
149 ledger_find(struct ledger_info
*li
)
153 for (l
= ledgers
; l
&& (li
->li_id
!= l
->id
); l
= l
->next
)
157 l
= (struct ledger
*)malloc(sizeof (*l
));
159 fprintf(stderr
, "Out of memory");
163 l
->entries
= li
->li_entries
;
174 ledger_update(pid_t pid
, struct ledger
*l
)
177 struct ledger_entry_info
*lei
;
183 arg
= (void *)(long)pid
;
184 lei
= (struct ledger_entry_info
*)malloc((size_t)(cnt
* sizeof (*lei
)));
185 if (ledger(LEDGER_ENTRY_INFO
, arg
, (caddr_t
)lei
, (caddr_t
)&cnt
) < 0) {
186 perror("ledger_info() failed: ");
193 get_proc_info(int pid
)
195 struct ledger_info li
;
196 struct ledger
*ledgerp
;
197 struct proc_list
*proc
;
203 arg
= (void *)(long)pid
;
205 if (ledger(LEDGER_INFO
, arg
, (caddr_t
)&li
, NULL
) < 0) {
207 if (errno
== ENOENT
|| errno
== ESRCH
)
210 perror("ledger_info() failed: ");
214 ledgerp
= ledger_find(&li
);
215 ledger_update(pid
, ledgerp
);
218 for (proc
= procs
; proc
; proc
= proc
->next
)
219 if (proc
->pid
== pid
)
222 proc
= (struct proc_list
*)malloc(sizeof (*proc
));
224 fprintf(stderr
, "Out of memory\n");
228 if (proc_name(pid
, proc
->name
, sizeof (proc
->name
)) == 0)
229 strlcpy(proc
->name
, "Error", sizeof (proc
->name
));
232 proc
->ledger
= ledgerp
;
240 pid_compare(const void *a
, const void *b
)
242 pid_t
*pid_a
= (pid_t
*)a
;
243 pid_t
*pid_b
= (pid_t
*)b
;
245 return (*pid_b
- *pid_a
);
255 cnt
= (int) get_kern_max_proc();
259 sz
= cnt
* sizeof(pid_t
);
260 pids
= (pid_t
*)malloc(sz
);
262 perror("can't allocate memory for proc buffer\n");
267 cnt
= proc_listallpids(pids
, sz
);
269 perror("failed to get list of active pids");
272 qsort(pids
, cnt
, sizeof (pid_t
), pid_compare
);
277 for (i
= 0; i
< cnt
; i
++)
278 get_proc_info(pids
[i
]);
283 print_num(int64_t num
, int64_t delta
)
285 const char *suf
= "";
293 if (num
== LEDGER_LIMIT_INFINITY
) {
294 printf("%10s ", "-");
298 if (llabs(num
) > 10000000000) {
301 } else if (llabs(num
) > 10000000) {
304 } else if (llabs(num
) > 100000) {
309 posneg
= (delta
< 0) ? '-' : ((delta
> 0) ? '+' : ' ');
313 numwidth
-= strlen(suf
);
315 printf("%*lld%s%c ", numwidth
, num
, suf
, posneg
);
321 struct ledger_entry_info
*info
, *old
;
326 printf("\n%5s %32s %32s %10s %10s %10s %10s %10s \n", "PID", "COMMAND",
327 "RESOURCE", "CREDITS", "DEBITS", "BALANCE", "LIMIT", "PERIOD");
329 for (p
= procs
; p
; p
= p
->next
) {
333 printf("%5d %32s ", p
->pid
, p
->name
);
336 info
= p
->ledger
->info
;
337 old
= p
->ledger
->old_info
;
338 for (i
= 0; i
< p
->ledger
->entries
; i
++) {
340 strcmp(group_print
, template[i
].lti_group
))
343 if (resource_print
&&
344 strcmp(resource_print
, template[i
].lti_name
))
348 printf("%5s %32s ", "", "");
349 printf("%32s ", template[i
].lti_name
);
351 d
= old
? info
[i
].lei_credit
- old
[i
].lei_credit
: 0;
352 print_num(info
[i
].lei_credit
, d
);
354 d
= old
? info
[i
].lei_debit
- old
[i
].lei_debit
: 0;
355 print_num(info
[i
].lei_debit
, d
);
357 d
= old
? info
[i
].lei_balance
- old
[i
].lei_balance
: 0;
358 print_num(info
[i
].lei_balance
, d
);
360 if (info
[i
].lei_limit
== LEDGER_LIMIT_INFINITY
) {
361 printf("%10s %10s", "none", "-");
363 print_num(info
[i
].lei_limit
, 0);
364 print_num(info
[i
].lei_refill_period
, 0);
377 struct proc_list
*p
, *pnext
, *plast
;
378 struct ledger
*l
, *lnext
, *llast
;
381 for (p
= procs
; p
; p
= pnext
) {
396 for (l
= ledgers
; l
; l
= lnext
) {
410 l
->old_info
= l
->info
;
424 printf("%s [-hdL] [-g group] [-p pid] [-r resource] [interval]\n", pname
);
428 main(int argc
, char **argv
)
435 while ((c
= getopt(argc
, argv
, "g:hdLp:r:")) != -1) {
438 group_print
= optarg
;
451 dump_template_info();
459 resource_print
= optarg
;
472 interval
= atoi(argv
[0]);
474 if (group_print
&& resource_print
) {
475 fprintf(stderr
, "Cannot specify both a resource and a group\n");