1/*
2 * Copyright (c) 2002-2004, 2008 Apple Computer, Inc.  All rights reserved.
3 *
4 * @APPLE_LICENSE_HEADER_START@
5 *
6 * The contents of this file constitute Original Code as defined in and
7 * are subject to the Apple Public Source License Version 1.1 (the
8 * "License").  You may not use this file except in compliance with the
9 * License.  Please obtain a copy of the License at
10 * http://www.apple.com/publicsource and read it before using this file.
11 *
12 * This Original Code and all software distributed under the License are
13 * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER
14 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
15 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
16 * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT.  Please see the
17 * License for the specific language governing rights and limitations
18 * under the License.
19 *
20 * @APPLE_LICENSE_HEADER_END@
21 */
22
23#include <stdlib.h>
24#include <sys/time.h>
25#include <mach/mach_time.h>
26#include "libtop.h"
27#include "cpu.h"
28#include "generic.h"
29#include "preferences.h"
30#include "log.h"
31#include "uinteger.h"
32
33extern const libtop_tsamp_t *tsamp;
34extern mach_timebase_info_data_t timebase_info;
35
36static bool cpu_insert_cell(struct statistic *s, const void *sample) {
37	const libtop_psamp_t *psamp = sample;
38	struct timeval elapsed, used;
39	char buf[10];
40	unsigned long long elapsed_us = 0, used_us = 0;
41	int whole = 0, part = 0;
42
43	if(0 == psamp->p_seq) {
44		whole = 0;
45		part = 0;
46
47		if(-1 == snprintf(buf, sizeof(buf), "%d.%1d", whole, part))
48			return true;
49
50		return generic_insert_cell(s, buf);
51	}
52
53
54	switch(top_prefs_get_mode()) {
55		case STATMODE_ACCUM:
56			timersub(&tsamp->time, &tsamp->b_time, &elapsed);
57			timersub(&psamp->total_time, &psamp->b_total_time, &used);
58			break;
59
60
61		case STATMODE_EVENT:
62		case STATMODE_DELTA:
63		case STATMODE_NON_EVENT:
64			timersub(&tsamp->time, &tsamp->p_time, &elapsed);
65			timersub(&psamp->total_time, &psamp->p_total_time, &used);
66			break;
67
68		default:
69			fprintf(stderr, "unhandled STATMOMDE in %s\n", __func__);
70			abort();
71	}
72
73	elapsed_us = (unsigned long long)elapsed.tv_sec * 1000000ULL
74		+ (unsigned long long)elapsed.tv_usec;
75
76	used_us = (unsigned long long)used.tv_sec * 1000000ULL
77		+ (unsigned long long)used.tv_usec;
78
79	/* Avoid a divide by 0 exception. */
80	if(elapsed_us > 0) {
81		whole = (used_us * 100ULL) / elapsed_us;
82		part = (((used_us * 100ULL) - (whole * elapsed_us)) * 10ULL) / elapsed_us;
83	}
84
85	//top_log("command %s whole %d part %d\n", psamp->command, whole, part);
86
87	if(-1 == snprintf(buf, sizeof(buf), "%d.%1d", whole, part))
88		return true;
89
90	return generic_insert_cell(s, buf);
91}
92
93static struct statistic_callbacks callbacks = {
94	.draw = generic_draw,
95	.resize_cells = generic_resize_cells,
96	.move_cells = generic_move_cells,
97	.get_request_size = generic_get_request_size,
98	.get_minimum_size = generic_get_minimum_size,
99	.insert_cell = cpu_insert_cell,
100	.reset_insertion = generic_reset_insertion
101};
102
103struct statistic *top_cpu_create(WINDOW *parent, const char *name) {
104	return create_statistic(STATISTIC_CPU, parent, NULL, &callbacks, name);
105}
106
107
108static bool cpu_me_insert_cell(struct statistic *s, const void *sample) {
109
110	const libtop_psamp_t *psamp = sample;
111	struct timeval elapsed;
112	char buf[10];
113	unsigned long long elapsed_ns = 0, used_ns = 0;
114
115	if(0 == psamp->p_seq) {
116
117		if(-1 == snprintf(buf, sizeof(buf), "%7.5f", 0))
118			return true;
119
120		return generic_insert_cell(s, buf);
121	}
122
123	switch(top_prefs_get_mode()) {
124		case STATMODE_ACCUM:
125			timersub(&tsamp->time, &tsamp->b_time, &elapsed);
126			used_ns = psamp->cpu_billed_to_me - psamp->b_cpu_billed_to_me;
127			break;
128
129
130		case STATMODE_EVENT:
131		case STATMODE_DELTA:
132		case STATMODE_NON_EVENT:
133			timersub(&tsamp->time, &tsamp->p_time, &elapsed);
134			used_ns = psamp->cpu_billed_to_me - psamp->p_cpu_billed_to_me;
135			break;
136
137		default:
138			fprintf(stderr, "unhandled STATMOMDE in %s\n", __func__);
139			abort();
140	}
141
142	used_ns = used_ns * timebase_info.numer / timebase_info.denom;
143
144	elapsed_ns = (unsigned long long)elapsed.tv_sec * 1000000000ULL
145		+ (unsigned long long)elapsed.tv_usec* 1000ULL;
146
147	//top_log("command %s whole %d part %d\n", psamp->command, whole, part);
148
149	if(-1 == snprintf(buf, sizeof(buf), "%7.5f", (((float)used_ns * 100) / (float)elapsed_ns)))
150		return true;
151
152	return generic_insert_cell(s, buf);
153}
154
155static void cpu_me_get_minimum_size(struct statistic *s) {
156	s->minimum_size.width = 7;
157	s->minimum_size.height = 1;
158}
159
160static struct statistic_callbacks callbacks1 = {
161	.draw = generic_draw,
162	.resize_cells = generic_resize_cells,
163	.move_cells = generic_move_cells,
164	.get_request_size = generic_get_request_size,
165	.get_minimum_size = cpu_me_get_minimum_size,
166	.insert_cell = cpu_me_insert_cell,
167	.reset_insertion = generic_reset_insertion
168};
169
170struct statistic *top_cpu_me_create(WINDOW *parent, const char *name) {
171	return create_statistic(STATISTIC_CPU_ME, parent, NULL, &callbacks1, name);
172}
173
174static bool cpu_others_insert_cell(struct statistic *s, const void *sample) {
175
176	const libtop_psamp_t *psamp = sample;
177	struct timeval elapsed;
178	char buf[10];
179	unsigned long long elapsed_ns = 0, used_ns = 0;
180
181	if(0 == psamp->p_seq) {
182
183		if(-1 == snprintf(buf, sizeof(buf), "%7.5f", 0))
184			return true;
185
186		return generic_insert_cell(s, buf);
187	}
188
189
190	switch(top_prefs_get_mode()) {
191		case STATMODE_ACCUM:
192			timersub(&tsamp->time, &tsamp->b_time, &elapsed);
193			used_ns = psamp->cpu_billed_to_others - psamp->b_cpu_billed_to_others;
194			break;
195
196
197		case STATMODE_EVENT:
198		case STATMODE_DELTA:
199		case STATMODE_NON_EVENT:
200			timersub(&tsamp->time, &tsamp->p_time, &elapsed);
201			used_ns = psamp->cpu_billed_to_others - psamp->p_cpu_billed_to_others;
202			break;
203
204		default:
205			fprintf(stderr, "unhandled STATMOMDE in %s\n", __func__);
206			abort();
207	}
208
209	used_ns = used_ns * timebase_info.numer / timebase_info.denom;
210
211	elapsed_ns = (unsigned long long)elapsed.tv_sec * 1000000000ULL
212		+ (unsigned long long)elapsed.tv_usec * 1000ULL;
213
214	//top_log("command %s whole %d part %d\n", psamp->command, whole, part);
215
216	if(-1 == snprintf(buf, sizeof(buf), "%7.5f", (((float)used_ns * 100) / (float)elapsed_ns)))
217		return true;
218
219	return generic_insert_cell(s, buf);
220}
221
222static void cpu_others_get_minimum_size(struct statistic *s) {
223	s->minimum_size.width =10 ;
224	s->minimum_size.height = 1;
225}
226
227static struct statistic_callbacks callbacks2 = {
228	.draw = generic_draw,
229	.resize_cells = generic_resize_cells,
230	.move_cells = generic_move_cells,
231	.get_request_size = generic_get_request_size,
232	.get_minimum_size = cpu_others_get_minimum_size,
233	.insert_cell = cpu_others_insert_cell,
234	.reset_insertion = generic_reset_insertion
235};
236
237struct statistic *top_cpu_others_create(WINDOW *parent, const char *name) {
238	return create_statistic(STATISTIC_CPU_OTHERS, parent, NULL, &callbacks2, name);
239}
240
241static bool boosts_insert_cell(struct statistic *s, const void *sample) {
242
243	const libtop_psamp_t *psamp = sample;
244	char buf1[GENERIC_INT_SIZE];
245	char buf2[GENERIC_INT_SIZE];
246	char buf[GENERIC_INT_SIZE * 2 + 3];
247
248	if (top_uinteger_format_result(buf1, sizeof(buf1),
249				psamp->assertcnt, psamp->p_assertcnt,
250				psamp->b_assertcnt)) {
251		return true;
252	}
253	if (top_uinteger_format_result(buf2, sizeof(buf2),
254				psamp->boosts, psamp->p_boosts,
255				psamp->b_boosts)) {
256		return true;
257	}
258	sprintf(buf, "%c%s[%s]", ((psamp->boost_donating) ? '*' : ' '), buf1, buf2);
259
260	return generic_insert_cell(s, buf);
261}
262
263static void boosts_get_minimum_size(struct statistic *s) {
264	generic_get_minimum_size(s);
265	s->minimum_size.width += 4;
266}
267
268static struct statistic_callbacks callbacks3 = {
269	.draw = generic_draw,
270	.resize_cells = generic_resize_cells,
271	.move_cells = generic_move_cells,
272	.get_request_size = generic_get_request_size,
273	.get_minimum_size = boosts_get_minimum_size,
274	.insert_cell = boosts_insert_cell,
275	.reset_insertion = generic_reset_insertion
276};
277
278struct statistic *top_boosts_create(WINDOW *parent, const char *name) {
279	return create_statistic(STATISTIC_BOOSTS, parent, NULL, &callbacks3, name);
280}
281