A
Adam Monsen
I kindly request a code review. If this is not an appropriate place
for my request, where might be?
Specific questions are in the QUESTIONS section of the code.
==========================================================================
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#define SECONDS_PER_DAY 86400
/*
wuptime - calculate uptime for cable modem based on columnar data
Copyright (C) 2004 Adam Monsen <[email protected]>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
USA
*/
/*
DESCRIPTION:
This program caculates total uptime and downtime of my cable modem.
Another program gathers input data based on weather it thinks the
modem is up or down. This program is 200 times faster than a Perl
script which does the same thing.
Here are a few lines of sample input (no tabs):
---------------------------8<---------------------------
1073410484 0
1073410540 0
1073410594 1
1073410982 1
1073411950 1
--------------------------->8---------------------------
The first column is a UNIX timestamp, the second column is a flag
indicating weather my cable modem was up (1) or down (0). The first
column must be an integer greater than 1. The second column must be
either 0 or 1. Each successive line must have a greater integer
value in the first column than the preceding line.
This program uses a 2-element queue to calculate uptime. The queue
stores two-dimensional arrays. When the queue is full, the time
delta
is calculated by subtracting the timestamp in the first element from
the timestamp in the second element. Since the timestamp must be
a positive integer, a value of 0 indicates the queue position is
empty.
The in-between time is interpolated as follows:
modem status went from down to down
=> all time in interval counts as downtime
modem status went from up to up
=> all time in interval counts as uptime
modem status went from up to down or down to up
=> all time in interval is split between up and downtime
Here's a Makefile for this program:
---------------------------8<---------------------------
# can't use -ansi with snprintf() since it's C99 or something
CFLAGS=-g -Wall -pedantic -O3
wuptime:
--------------------------->8---------------------------
QUESTIONS:
1. would using structs instead of two-element arrays in the queue be
slower? Should I do it anyway?
2. I use fgets() to read the input file. This will fail if the file
contains NULLs, correct?
3. is there a convenient way to turn seconds into days, hours,
minutes, etc? Perl has Time:uration, for instance.
4. do I need some other header file to use snprintf()? The -ansi
compiler flag causes GCC to complain.
*/
/* populates a queue object */
void
push (int subqueue[], const int timestamp, const int errorcode)
{
subqueue[0] = timestamp;
subqueue[1] = errorcode;
}
/* moves the 2nd position of the queue into the 1st position, and
* marks the 2nd position as empty */
void
shift (int queue[][2])
{
queue[0][0] = queue[1][0];
queue[0][1] = queue[1][1];
queue[1][0] = 0;
/* queue[1][1] = 0; ... not necessary, we only look at [0] */
}
/* modifies total_uptime and total_downtime according to what's in
* the queue */
void
process_uptime (int queue[][2], long *total_uptime, long
*total_downtime)
{
long time_delta = queue[1][0] - queue[0][0];
if (!(queue[0][1] & queue[1][1]))
*total_downtime += time_delta; /* down to down, all down */
else if (queue[0][1] & queue[1][1])
*total_uptime += time_delta; /* up to up, all up */
else if (queue[0][1] ^ queue[1][1])
{
/* down to up or up to down, split the difference */
long half_time_delta = time_delta / 2;
*total_uptime += half_time_delta;
*total_downtime += half_time_delta;
}
}
int
main (void)
{
long total_uptime = 0;
long total_downtime = 0;
FILE *p_datafile = NULL;
char *p = NULL;
const char filename[] = "modem_uptime_data.txt";
char line[BUFSIZ];
/*
queue = { {1076924581, 1 }, {1076926382, 0 } };
| ^^^^^^^^^^ ^^^^^^ ^^^^^^^^^^ ^^^^^^
columns = timestamp status , timestamp status
*/
int queue[2][2] = { {0, 0}, {0, 0} };
printf ("Trying to open %s...\n", filename);
if ((p_datafile = fopen (filename, "r")) == NULL)
{
char errstr[BUFSIZ];
snprintf (errstr, BUFSIZ, "Error opening %s", filename);
perror (errstr);
exit (1);
}
while ((fgets (line, sizeof line, p_datafile)) != NULL)
{
int timestamp, errorcode;
if ((p = strchr (line, '\n')) != NULL)
*p = '\0';
sscanf (line, "%d\t%d", ×tamp, &errorcode);
push (queue[1], timestamp, errorcode);
if (queue[0][0] && queue[1][0])
process_uptime (queue, &total_uptime, &total_downtime);
shift (queue);
}
printf ("Uptime: %ld days\n", total_uptime / SECONDS_PER_DAY);
printf ("Downtime: %ld days\n", total_downtime / SECONDS_PER_DAY);
fclose (p_datafile);
return EXIT_SUCCESS;
}
for my request, where might be?
Specific questions are in the QUESTIONS section of the code.
==========================================================================
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#define SECONDS_PER_DAY 86400
/*
wuptime - calculate uptime for cable modem based on columnar data
Copyright (C) 2004 Adam Monsen <[email protected]>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
USA
*/
/*
DESCRIPTION:
This program caculates total uptime and downtime of my cable modem.
Another program gathers input data based on weather it thinks the
modem is up or down. This program is 200 times faster than a Perl
script which does the same thing.
Here are a few lines of sample input (no tabs):
---------------------------8<---------------------------
1073410484 0
1073410540 0
1073410594 1
1073410982 1
1073411950 1
--------------------------->8---------------------------
The first column is a UNIX timestamp, the second column is a flag
indicating weather my cable modem was up (1) or down (0). The first
column must be an integer greater than 1. The second column must be
either 0 or 1. Each successive line must have a greater integer
value in the first column than the preceding line.
This program uses a 2-element queue to calculate uptime. The queue
stores two-dimensional arrays. When the queue is full, the time
delta
is calculated by subtracting the timestamp in the first element from
the timestamp in the second element. Since the timestamp must be
a positive integer, a value of 0 indicates the queue position is
empty.
The in-between time is interpolated as follows:
modem status went from down to down
=> all time in interval counts as downtime
modem status went from up to up
=> all time in interval counts as uptime
modem status went from up to down or down to up
=> all time in interval is split between up and downtime
Here's a Makefile for this program:
---------------------------8<---------------------------
# can't use -ansi with snprintf() since it's C99 or something
CFLAGS=-g -Wall -pedantic -O3
wuptime:
--------------------------->8---------------------------
QUESTIONS:
1. would using structs instead of two-element arrays in the queue be
slower? Should I do it anyway?
2. I use fgets() to read the input file. This will fail if the file
contains NULLs, correct?
3. is there a convenient way to turn seconds into days, hours,
minutes, etc? Perl has Time:uration, for instance.
4. do I need some other header file to use snprintf()? The -ansi
compiler flag causes GCC to complain.
*/
/* populates a queue object */
void
push (int subqueue[], const int timestamp, const int errorcode)
{
subqueue[0] = timestamp;
subqueue[1] = errorcode;
}
/* moves the 2nd position of the queue into the 1st position, and
* marks the 2nd position as empty */
void
shift (int queue[][2])
{
queue[0][0] = queue[1][0];
queue[0][1] = queue[1][1];
queue[1][0] = 0;
/* queue[1][1] = 0; ... not necessary, we only look at [0] */
}
/* modifies total_uptime and total_downtime according to what's in
* the queue */
void
process_uptime (int queue[][2], long *total_uptime, long
*total_downtime)
{
long time_delta = queue[1][0] - queue[0][0];
if (!(queue[0][1] & queue[1][1]))
*total_downtime += time_delta; /* down to down, all down */
else if (queue[0][1] & queue[1][1])
*total_uptime += time_delta; /* up to up, all up */
else if (queue[0][1] ^ queue[1][1])
{
/* down to up or up to down, split the difference */
long half_time_delta = time_delta / 2;
*total_uptime += half_time_delta;
*total_downtime += half_time_delta;
}
}
int
main (void)
{
long total_uptime = 0;
long total_downtime = 0;
FILE *p_datafile = NULL;
char *p = NULL;
const char filename[] = "modem_uptime_data.txt";
char line[BUFSIZ];
/*
queue = { {1076924581, 1 }, {1076926382, 0 } };
| ^^^^^^^^^^ ^^^^^^ ^^^^^^^^^^ ^^^^^^
columns = timestamp status , timestamp status
*/
int queue[2][2] = { {0, 0}, {0, 0} };
printf ("Trying to open %s...\n", filename);
if ((p_datafile = fopen (filename, "r")) == NULL)
{
char errstr[BUFSIZ];
snprintf (errstr, BUFSIZ, "Error opening %s", filename);
perror (errstr);
exit (1);
}
while ((fgets (line, sizeof line, p_datafile)) != NULL)
{
int timestamp, errorcode;
if ((p = strchr (line, '\n')) != NULL)
*p = '\0';
sscanf (line, "%d\t%d", ×tamp, &errorcode);
push (queue[1], timestamp, errorcode);
if (queue[0][0] && queue[1][0])
process_uptime (queue, &total_uptime, &total_downtime);
shift (queue);
}
printf ("Uptime: %ld days\n", total_uptime / SECONDS_PER_DAY);
printf ("Downtime: %ld days\n", total_downtime / SECONDS_PER_DAY);
fclose (p_datafile);
return EXIT_SUCCESS;
}