utils.c 4.7 KB
Newer Older
Leigh B. Stoller's avatar
Leigh B. Stoller committed
1 2
/*
 * EMULAB-COPYRIGHT
3
 * Copyright (c) 2000-2003 University of Utah and the Flux Group.
Leigh B. Stoller's avatar
Leigh B. Stoller committed
4 5 6
 * All rights reserved.
 */

7 8 9 10 11 12 13 14 15 16 17
/*
 * Some simple common utility functions.
 */

#include <sys/types.h>
#include <ctype.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <errno.h>
#include <sys/time.h>
18
#include <sys/sysctl.h>
19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37
#include "decls.h"

/*
 * Return current time in a string printable format. Caller must absorb
 * the string. 
 */
char *
CurrentTimeString(void)
{
	static char	buf[32];
	time_t		curtime;
	static struct tm tm;
	
	time(&curtime);
	strftime(buf, sizeof(buf), "%T", localtime_r(&curtime, &tm));

	return buf;
}

38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83
int
sleeptime(unsigned int usecs, char *str)
{
	static unsigned int clockres_us;
	int nusecs;

	if (clockres_us == 0) {
		struct clockinfo ci;
		int cisize = sizeof(ci);

		ci.hz = 0;
		if (sysctlbyname("kern.clockrate", &ci, &cisize, 0, 0) < 0 ||
		    ci.hz == 0) {
			warning("cannot get clock resolution, assuming 100HZ");
			clockres_us = 10000;
		} else
			clockres_us = ci.tick;
		if (debug)
			log("clock resolution: %d us", clockres_us);
	}
	nusecs = ((usecs + clockres_us - 1) / clockres_us) * clockres_us;
/*
 * Rounding is actually a bad idea.  Say the kernel has just gone past
 * system tick N.  If we round a value of 1/2 tick up to 1 tick and then
 * call sleep, the kernel will add our 1 tick to the current value to get
 * a time slightly past tick N+1.  It will then round that up to N+2,
 * so we effectively sleep almost two full ticks.  But if we don't round
 * the tick, then adding that to the current time might yield a value
 * less than N+1, which will round up to N+1 and we will at worst sleep
 * one full tick.
 */
#if 0
	if (nusecs != usecs && str != NULL)
		warning("%s: rounded to %d from %d "
			"due to clock resolution", str, nusecs, usecs);
#else
	if (nusecs != usecs && str != NULL) {
		warning("%s: may be up to %d (instead of %d) "
			"due to clock resolution", str, nusecs, usecs);
	}
	nusecs = usecs;
#endif

	return nusecs;
}

84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109
/*
 * Sleep. Basically wraps nanosleep, but since the threads package uses
 * signals, it keeps ending early!
 */
int
fsleep(unsigned int usecs)
{
	struct timespec time_to_sleep, time_not_slept;
	int	foo;

	time_to_sleep.tv_nsec  = (usecs % 1000000) * 1000;
	time_to_sleep.tv_sec   = usecs / 1000000;
	time_not_slept.tv_nsec = 0;
	time_not_slept.tv_sec  = 0;

	while ((foo = nanosleep(&time_to_sleep, &time_not_slept)) != 0) {
		if (foo < 0 && errno != EINTR) {
			return -1;
		}
		time_to_sleep.tv_nsec  = time_not_slept.tv_nsec;
		time_to_sleep.tv_sec   = time_not_slept.tv_sec;
		time_not_slept.tv_nsec = 0;
		time_not_slept.tv_sec  = 0;
	}
	return 0;
}
110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167

#ifdef STATS
void
ClientStatsDump(unsigned int id, ClientStats_t *stats)
{
	int seconds;

	switch (stats->version) {
	case 1:
		/* compensate for start delay */
		stats->u.v1.runmsec -= stats->u.v1.delayms;
		while (stats->u.v1.runmsec < 0) {
			stats->u.v1.runsec--;
			stats->u.v1.runmsec += 1000;
		}

		log("Client %u Performance:", id);
		log("  runtime:                %d.%03d sec",
		    stats->u.v1.runsec, stats->u.v1.runmsec);
		log("  start delay:            %d.%03d sec",
		    stats->u.v1.delayms/1000, stats->u.v1.delayms%1000);
		seconds = stats->u.v1.runsec;
		if (seconds == 0)
			seconds = 1;
		log("  real data written:      %qu (%ld Bps)",
		    stats->u.v1.rbyteswritten,
		    (long)(stats->u.v1.rbyteswritten/seconds));
		log("  effective data written: %qu (%ld Bps)",
		    stats->u.v1.ebyteswritten,
		    (long)(stats->u.v1.ebyteswritten/seconds));
		log("Client %u Params:", id);
		log("  chunk/block size:     %d/%d",
		    CHUNKSIZE, BLOCKSIZE);
		log("  chunk buffers:        %d",
		    stats->u.v1.chunkbufs);
		log("  readahead/inprogress: %d/%d",
		    stats->u.v1.maxreadahead, stats->u.v1.maxinprogress);
		log("  recv timo/count:      %d/%d",
		    stats->u.v1.pkttimeout, stats->u.v1.idletimer);
		log("  re-request delay:     %d",
		    stats->u.v1.redodelay);
		log("  writer idle delay:    %d",
		    stats->u.v1.idledelay);
		log("  randomize requests:   %d",
		    stats->u.v1.randomize);
		log("Client %u Stats:", id);
		log("  net thread idle/blocked:        %d/%d",
		    stats->u.v1.recvidles, stats->u.v1.nofreechunks);
		log("  decompress thread idle/blocked: %d/%d",
		    stats->u.v1.nochunksready, stats->u.v1.decompidles);
		log("  disk thread idle:               %d",
		    stats->u.v1.writeridles);
		log("  join/request msgs:      %d/%d",
		    stats->u.v1.joinattempts, stats->u.v1.requests);
		log("  dupblocks(chunk done):  %d",
		    stats->u.v1.dupchunk);
		log("  dupblocks(in progress): %d",
		    stats->u.v1.dupblock);
168
		log("  partial chunk requests: %d",
169 170 171 172 173 174 175 176 177
		    stats->u.v1.lostblocks);
		break;

	default:
		log("Unknown stats version %d", stats->version);
		break;
	}
}
#endif