Skip to content

Instantly share code, notes, and snippets.

@mheffner
Created May 13, 2011 19:21
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save mheffner/971137 to your computer and use it in GitHub Desktop.
Save mheffner/971137 to your computer and use it in GitHub Desktop.
Report gettimeofday, TSC and getrusage(self) periodically while performing I/O workload.
/*
* Dumps the value of gettimeofday(), the TSC, and
* getrusage(RUSAGE_SELF) every two seconds while performing some fake
* I/O workload on a /tmp file.
*
* Build: gcc -o readtsc readtsc.c -lrt
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdint.h>
#include <inttypes.h>
#include <sys/time.h>
#include <sys/resource.h>
#include <signal.h>
#include <sys/types.h>
#include <unistd.h>
#include <time.h>
static uint64_t
get_time(void)
{
struct timeval tv;
gettimeofday(&tv, NULL);
return (tv.tv_sec * 1000000L) + tv.tv_usec;
}
__inline__ uint64_t
get_tsc(void) {
uint32_t lo, hi;
__asm__ __volatile__ ( /* serialize */
"xorl %%eax,%%eax \n cpuid"
::: "%rax", "%rbx", "%rcx", "%rdx");
/* We cannot use "=A", since this would use %rax on x86_64 and
* return only the lower 32bits of the TSC
*/
__asm__ __volatile__ ("rdtsc" : "=a" (lo), "=d" (hi));
return (uint64_t)hi << 32 | lo;
}
static uint64_t
get_usage(void)
{
struct rusage usage;
struct timeval usage_time;
uint64_t current_usage;
getrusage(RUSAGE_SELF, &usage);
usage_time.tv_usec = usage.ru_utime.tv_usec + usage.ru_stime.tv_usec;
usage_time.tv_sec = usage.ru_utime.tv_sec + usage.ru_stime.tv_sec;
if (usage_time.tv_usec >= 1000000)
{
usage_time.tv_usec -= 1000000;
usage_time.tv_sec++;
}
current_usage = (uint64_t)usage_time.tv_sec * 1000000 +
(uint64_t)usage_time.tv_usec;
return current_usage;
}
uint64_t base_tod, base_tsc, base_usage;
void
print_time(int sig)
{
int64_t tod, tsc, usage;
tod = get_time();
tsc = get_tsc();
usage = get_usage();
tod -= base_tod;
tsc -= base_tsc;
usage -= base_usage;
printf("{ \"timeofday\" : %" PRId64 ", \"tsc\" : %" PRId64 ", \"usage\" : %" PRId64 " }\n",
tod, tsc, usage);
fflush(stdout);
}
#define TEMPLATE "/tmp/tempXXXXXXXXXX"
int
main(int ac, char **av)
{
struct sigevent se;
timer_t timer;
struct itimerspec ts;
struct sigaction act;
char tmp[] = TEMPLATE;
sigfillset(&act.sa_mask);
sigdelset(&act.sa_mask, SIGRTMAX - 3);
act.sa_flags = SA_RESTART;
act.sa_handler = print_time;
if (sigaction(SIGRTMAX - 3, &act, NULL) != 0) {
perror("sigaction");
exit(1);
}
memset(&se, 0, sizeof(se));
se.sigev_notify = SIGEV_SIGNAL;
se.sigev_signo = SIGRTMAX - 3;
se.sigev_value.sival_int = 0;
if (timer_create(CLOCK_REALTIME, &se, &timer) != 0) {
perror("timer_create");
exit(1);
}
ts.it_value.tv_sec = 2;
ts.it_value.tv_nsec = 0;
ts.it_interval.tv_sec = 2;
ts.it_interval.tv_nsec = 0;
/* Initialize starting. */
base_tod = get_time();
base_tsc = get_tsc();
base_usage = get_usage();
/* Start timer */
timer_settime(timer, 0, &ts, NULL);
/* Perform some fake I/O workload. */
while(1) {
int fd;
size_t size = 1024 * 1024 * 1024;
size_t bs = 8192;
size_t sync_size = 8192 * 4;
char buf[8192] = "";
size_t i;
ssize_t w;
fd = mkstemp(tmp);
unlink(tmp);
/* write a size byte file */
for (i = 0; i < size; i += bs) {
w = write(fd, buf, bs);
if (w < 0 || (size_t)w != bs) {
perror("write");
exit(1);
}
if ((i % sync_size) == 0)
fsync(fd);
}
fsync(fd);
lseek(fd, 0, SEEK_SET);
/* now read */
for (i = 0; i < size; i += bs) {
read(fd, buf, bs);
}
close(fd);
sprintf(tmp, TEMPLATE);
}
return 0;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment