1/*
2 *   Copyright (c) International Business Machines Corp., 2001-2004
3 *
4 *   This program is free software;  you can redistribute it and/or modify
5 *   it under the terms of the GNU General Public License as published by
6 *   the Free Software Foundation; either version 2 of the License, or
7 *   (at your option) any later version.
8 *
9 *   This program is distributed in the hope that it will be useful,
10 *   but WITHOUT ANY WARRANTY;  without even the implied warranty of
11 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See
12 *   the GNU General Public License for more details.
13 *
14 *   You should have received a copy of the GNU General Public License
15 *   along with this program;  if not, write to the Free Software
16 *   Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
17 */
18#include <sys/types.h>
19#include <sys/stat.h>
20#include <sys/resource.h>
21#include <sys/wait.h>
22#include <sys/time.h>
23#include <sys/select.h>
24#include <stdio.h>
25#include <unistd.h>
26#include <stdlib.h>
27#include <assert.h>
28#include <string.h>
29#include <limits.h>
30#include <errno.h>
31#include <pthread.h>
32
33#include "config.h"
34#include "fh.h"
35#include "util.h"
36
37uint64_t ffsb_get_filesize(char *name)
38{
39#ifndef HAVE_STAT64
40#define STAT(a, b) do { stat((a), (b)); } while (0)
41	struct stat filestat;
42#else
43#define STAT(a, b) do { stat64((a), (b)); } while (0)
44	struct stat64 filestat;
45#endif
46
47	STAT(name, &filestat);
48	return (uint64_t) filestat.st_size;
49#undef STAT
50}
51
52void *ffsb_malloc(size_t size)
53{
54	void *ptr = malloc((size));
55	assert(ptr != NULL);
56	memset(ptr, 0, size);
57	return ptr;
58}
59
60void *ffsb_realloc(void *ptr, size_t size)
61{
62	void *tmp;
63	/* printf("ffsb_realloc: ptr = %p  size = %ld\n",ptr,size); */
64
65	if (ptr == NULL)
66		return ffsb_malloc(size);
67
68	tmp = realloc(ptr, size);
69	assert(ptr != NULL);
70	ptr = tmp;
71	return ptr;
72}
73
74void *ffsb_align_4k(void *ptr)
75{
76	unsigned long mask = ~(0xfff);	/* 12 zeros at the end */
77	void *ret = (void *)((unsigned long)ptr & mask);
78	/* printf("align_4k got %p returning %p\n",ptr,ret); */
79	return ret;
80}
81
82char *ffsb_strdup(const char *str)
83{
84	int len = strlen(str);
85	char *dup = ffsb_malloc(len + 1);
86	/* !!! am I off by one here ?? */
87	strncpy(dup, str, len + 1);
88	return dup;
89}
90
91size_t ffsb_strnlen(const char *str, size_t maxlen)
92{
93	size_t index = 0;
94
95	while (index < maxlen) {
96		if (str[index] == '\0')
97			break;
98		index++;
99	}
100	return index;
101}
102
103/* not perfect, in case we are somehow interrupted it's borked */
104void ffsb_sleep(unsigned secs)
105{
106	struct timeval tv = { 0, 0 };
107	tv.tv_sec = secs;
108	select(0, NULL, NULL, NULL, &tv);
109}
110
111char *ffsb_printsize(char *buf, double size, int bufsize)
112{
113	if (size >= 1024 * 1024 * 1024)
114		snprintf(buf, bufsize, "%.3gGB", size / (1024 * 1024 * 1024));
115	else if (size >= 1024 * 1024)
116		snprintf(buf, bufsize, "%.3gMB", size / (1024 * 1024));
117	else if (size >= 1024)
118		snprintf(buf, bufsize, "%.3gKB", size / 1024);
119	else
120		snprintf(buf, bufsize, "%.3gB", size);
121
122	return buf;
123}
124
125void ffsb_mkdir(char *dirname)
126{
127	if (mkdir(dirname, S_IRWXU) < 0) {
128		fprintf(stderr, "Error creating %s\n", dirname);
129		perror("mkdir");
130		exit(1);
131	}
132}
133
134struct timeval tvsub(struct timeval t1, struct timeval t0)
135{
136	struct timeval tdiff;
137	tdiff.tv_sec = t1.tv_sec - t0.tv_sec;
138	tdiff.tv_usec = t1.tv_usec - t0.tv_usec;
139	if (tdiff.tv_usec < 0)
140		tdiff.tv_sec--, tdiff.tv_usec += 1000000;
141	return tdiff;
142}
143
144struct timeval tvadd(struct timeval t1, struct timeval t0)
145{
146	struct timeval tdiff;
147	tdiff.tv_sec = t1.tv_sec + t0.tv_sec;
148	tdiff.tv_usec = t1.tv_usec + t0.tv_usec;
149	if (tdiff.tv_usec > 1000000)
150		tdiff.tv_sec++, tdiff.tv_usec -= 1000000;
151	return tdiff;
152}
153
154double tvtodouble(struct timeval *t)
155{
156	return ((double)t->tv_sec * (1000000.0f) + (double)t->tv_usec) /
157	    1000000.0f;
158}
159
160double cpu_so_far(void)
161{
162	struct rusage rusage;
163
164	getrusage(RUSAGE_SELF, &rusage);
165
166	return
167	    ((double)rusage.ru_utime.tv_sec) +
168	    (((double)rusage.ru_utime.tv_usec) / 1000000.0) +
169	    ((double)rusage.ru_stime.tv_sec) +
170	    (((double)rusage.ru_stime.tv_usec) / 1000000.0);
171}
172
173double cpu_so_far_children(void)
174{
175	struct rusage rusage;
176
177	getrusage(RUSAGE_CHILDREN, &rusage);
178
179	return
180	    ((double)rusage.ru_utime.tv_sec) +
181	    (((double)rusage.ru_utime.tv_usec) / 1000000.0) +
182	    ((double)rusage.ru_stime.tv_sec) +
183	    (((double)rusage.ru_stime.tv_usec) / 1000000.0);
184}
185
186/* !!!! check portability */
187float getfsutil(char *dirname)
188{
189	struct statvfs64 fsdata;
190
191	statvfs64(dirname, &fsdata);
192
193/* 	return (float)(fsdata.f_blocks-fsdata.f_bfree)/ */
194/* 		(float)(fsdata.f_blocks-fsdata.f_bfree+fsdata.f_bavail); */
195	return (float)(((float)(fsdata.f_blocks - fsdata.f_bfree)) /
196		       ((float)fsdata.f_blocks));
197}
198
199uint64_t getfsutil_size(char *dirname)
200{
201	struct statvfs64 fsdata;
202	statvfs64(dirname, &fsdata);
203
204	return (fsdata.f_blocks - fsdata.f_bfree) * fsdata.f_bsize;
205}
206
207int ffsb_system(char *command)
208{
209	int pid = 0, status;
210	extern char **environ;
211
212	if (command == NULL)
213		return 1;
214	pid = fork();
215	if (pid == -1)
216		return -1;
217	if (pid == 0) {
218		char *argv[4];
219		argv[0] = "sh";
220		argv[1] = "-c";
221		argv[2] = command;
222		argv[3] = 0;
223		execve("/bin/sh", argv, environ);
224		exit(127);
225	}
226	do {
227		if (waitpid(pid, &status, 0) == -1) {
228			if (errno != EINTR)
229				return -1;
230		} else
231			return status;
232	} while (1);
233}
234
235void ffsb_sync()
236{
237	struct timeval starttime, endtime, difftime;
238	printf("Syncing()...");
239	fflush(stdout);
240	gettimeofday(&starttime, NULL);
241	sync();
242	gettimeofday(&endtime, NULL);
243	timersub(&endtime, &starttime, &difftime);
244	printf("%ld sec\n", difftime.tv_sec);
245}
246
247void ffsb_getrusage(struct rusage *ru_self, struct rusage *ru_children)
248{
249	int ret = 0;
250/* 	printf("cpu_so_far is %lf\n",cpu_so_far()); */
251/* 	printf("cpu_so_far_children is %lf\n",cpu_so_far_children()); */
252	ret = getrusage(RUSAGE_SELF, ru_self);
253	if (ret < 0)
254		perror("getrusage self");
255
256/* 	printf("self returned %d\n",ret); */
257	ret = getrusage(RUSAGE_CHILDREN, ru_children);
258	if (ret < 0)
259		perror("getrusage children");
260/* 	printf("children returned %d\n",ret); */
261}
262
263void ffsb_milli_sleep(unsigned time)
264{
265	struct timeval tv = { 0, 0 };
266	if (!time)
267		return;
268	tv.tv_usec = time * 1000;
269	select(0, NULL, NULL, NULL, &tv);
270}
271
272void ffsb_micro_sleep(unsigned time)
273{
274	struct timeval tv = { 0, 0 };
275	if (!time)
276		return;
277	tv.tv_usec = time;
278	select(0, NULL, NULL, NULL, &tv);
279}
280
281void ffsb_barrier_init(ffsb_barrier_t * fb, unsigned count)
282{
283	memset(fb, 0, sizeof(*fb));
284	pthread_mutex_init(&fb->plock, NULL);
285	pthread_cond_init(&fb->pcond, NULL);
286	fb->required_count = count;
287}
288
289void ffsb_barrier_wait(ffsb_barrier_t * fb)
290{
291	pthread_mutex_lock(&fb->plock);
292
293	fb->current_count++;
294
295	if (fb->current_count == fb->required_count)
296		pthread_cond_broadcast(&fb->pcond);
297	else
298		while (fb->current_count != fb->required_count)
299			pthread_cond_wait(&fb->pcond, &fb->plock);
300
301	pthread_mutex_unlock(&fb->plock);
302}
303
304void ffsb_unbuffer_stdout(void)
305{
306#ifndef SETVBUF_REVERSED
307	setvbuf(stdout, NULL, _IONBF, 0);
308#else
309	setvbuf(stdout, _IONBF, NULL, 0);
310#endif
311}
312
313void ffsb_bench_gettimeofday(void)
314{
315	unsigned long i = 0;
316	uint64_t total_usec;
317	uint64_t average = 0;
318	struct timeval starttime, endtime, junk, difftime;
319	gettimeofday(&starttime, NULL);
320	for (i = 0; i < 1000000; i++)
321		gettimeofday(&junk, NULL);
322	gettimeofday(&endtime, NULL);
323	timersub(&endtime, &starttime, &difftime);
324	total_usec = difftime.tv_sec * 1000000;
325	total_usec += difftime.tv_usec;
326	average = total_usec / 1000ull;
327	printf("average time for gettimeofday(): %llu nsec\n", average);
328}
329
330void ffsb_bench_getpid(void)
331{
332	unsigned long i = 0;
333	uint64_t total_usec;
334	uint64_t average = 0;
335	struct timeval starttime, endtime, difftime;
336	gettimeofday(&starttime, NULL);
337	for (i = 0; i < 1000000; i++)
338		getpid();
339	gettimeofday(&endtime, NULL);
340	timersub(&endtime, &starttime, &difftime);
341	total_usec = difftime.tv_sec * 1000000;
342	total_usec += difftime.tv_usec;
343	average = total_usec / 1000ull;
344	printf("average time for getpid(): %llu nsec\n", average);
345}
346