Discussion:
[Linuxptp-devel] [PATCH 02/13] Move Unix domain sockets to /var/run.
Miroslav Lichvar
2013-02-05 16:36:05 UTC
Permalink
According to FHS, /var/run is the right place for them.

Signed-off-by: Miroslav Lichvar <***@redhat.com>
---
phc2sys.c | 2 +-
pmc.8 | 2 +-
pmc.c | 4 ++--
uds.h | 2 +-
4 files changed, 5 insertions(+), 5 deletions(-)

diff --git a/phc2sys.c b/phc2sys.c
index 3d0f009..8fddfa9 100644
--- a/phc2sys.c
+++ b/phc2sys.c
@@ -331,7 +331,7 @@ static int run_pmc(int wait_sync, int *utc_offset)
TIME_PROPERTIES_DATA_SET
};

- pmc = pmc_create(TRANS_UDS, "/tmp/phc2sys", 0, 0, 0);
+ pmc = pmc_create(TRANS_UDS, "/var/run/phc2sys", 0, 0, 0);
if (!pmc) {
fprintf(stderr, "failed to create pmc\n");
return -1;
diff --git a/pmc.8 b/pmc.8
index 568b311..dfe71bb 100644
--- a/pmc.8
+++ b/pmc.8
@@ -64,7 +64,7 @@ Specify the boundary hops value in sent messages. The default is 1.
Specify the domain number in sent messages. The default is 0.
.TP
.BI \-i " interface"
-Specify the network interface. The default is /tmp/pmc for the Unix Domain
+Specify the network interface. The default is /var/run/pmc for the Unix Domain
Socket transport and eth0 for the other transports.
.TP
.BI \-t " transport-specific-field"
diff --git a/pmc.c b/pmc.c
index 3f94985..2736d85 100644
--- a/pmc.c
+++ b/pmc.c
@@ -392,7 +392,7 @@ static void usage(char *progname)
" -d [num] domain number, default 0\n"
" -h prints this message and exits\n"
" -i [dev] interface device to use, default 'eth0'\n"
- " for network and '/tmp/pmc' for UDS.\n"
+ " for network and '/var/run/pmc' for UDS.\n"
" -t [hex] transport specific field, default 0x0\n"
" -v prints the software version and exits\n"
"\n",
@@ -456,7 +456,7 @@ int main(int argc, char *argv[])
}

if (!iface_name) {
- iface_name = transport_type == TRANS_UDS ? "/tmp/pmc" : "eth0";
+ iface_name = transport_type == TRANS_UDS ? "/var/run/pmc" : "eth0";
}

print_set_progname(progname);
diff --git a/uds.h b/uds.h
index 3760eb8..24effa8 100644
--- a/uds.h
+++ b/uds.h
@@ -26,7 +26,7 @@
/**
* Address of the server.
*/
-#define UDS_PATH "/tmp/ptp4l"
+#define UDS_PATH "/var/run/ptp4l"

/**
* Allocate an instance of a UDS transport.
--
1.7.11.7
Miroslav Lichvar
2013-02-05 16:36:06 UTC
Permalink
Add a batch mode, where the commands are taken from the command line
instead of the standard input.

Signed-off-by: Miroslav Lichvar <***@redhat.com>
---
pmc.8 | 8 ++++----
pmc.c | 39 +++++++++++++++++++++++++++++++--------
2 files changed, 35 insertions(+), 12 deletions(-)

diff --git a/pmc.8 b/pmc.8
index dfe71bb..1128bf7 100644
--- a/pmc.8
+++ b/pmc.8
@@ -22,14 +22,14 @@ pmc \- PTP management client
.BI \-t " transport-specific-field"
] [
.B \-v
-]
+] [ command ] ...

.SH DESCRIPTION
.B pmc
is a program which implements a PTP management client according to IEEE
-standard 1588. The program reads from the standard input actions specified by
-name and management ID, sends them over the selected transport and prints any
-received replies. There are three actions supported:
+standard 1588. The program reads from the standard input or from the command
+line actions specified by name and management ID, sends them over the selected
+transport and prints any received replies. There are three actions supported:
.B GET
retrieves the specified information,
.B SET
diff --git a/pmc.c b/pmc.c
index 2736d85..5e000bb 100644
--- a/pmc.c
+++ b/pmc.c
@@ -381,7 +381,7 @@ static int do_command(char *str)
static void usage(char *progname)
{
fprintf(stderr,
- "\nusage: %s [options]\n\n"
+ "\nusage: %s [options] [commands]\n\n"
" Network Transport\n\n"
" -2 IEEE 802.3\n"
" -4 UDP IPV4 (default)\n"
@@ -402,8 +402,8 @@ static void usage(char *progname)
int main(int argc, char *argv[])
{
char *iface_name = NULL, *progname;
- int c, cnt, length, tmo = -1;
- char line[1024];
+ int c, cnt, length, tmo = -1, batch_mode = 0;
+ char line[1024], *command = NULL;
enum transport_type transport_type = TRANS_UDP_IPV4;
UInteger8 boundary_hops = 1, domain_number = 0, transport_specific = 0;
struct ptp_message *msg;
@@ -458,6 +458,9 @@ int main(int argc, char *argv[])
if (!iface_name) {
iface_name = transport_type == TRANS_UDS ? "/var/run/pmc" : "eth0";
}
+ if (optind < argc) {
+ batch_mode = 1;
+ }

print_set_progname(progname);
print_set_syslog(1);
@@ -469,12 +472,28 @@ int main(int argc, char *argv[])
return -1;
}

- pollfd[0].fd = STDIN_FILENO;
- pollfd[0].events = POLLIN|POLLPRI;
+ pollfd[0].fd = batch_mode ? -1 : STDIN_FILENO;
pollfd[1].fd = pmc_get_transport_fd(pmc);
- pollfd[1].events = POLLIN|POLLPRI;

while (1) {
+ if (batch_mode && !command) {
+ if (optind < argc) {
+ command = argv[optind++];
+ } else {
+ /* No more commands, wait a bit for
+ any outstanding replies and exit. */
+ tmo = 100;
+ }
+ }
+
+ pollfd[0].events = 0;
+ pollfd[1].events = POLLIN | POLLPRI;
+
+ if (!batch_mode && !command)
+ pollfd[0].events |= POLLIN | POLLPRI;
+ if (command)
+ pollfd[1].events |= POLLOUT;
+
cnt = poll(pollfd, N_FD, tmo);
if (cnt < 0) {
if (EINTR == errno) {
@@ -505,9 +524,13 @@ int main(int argc, char *argv[])
continue;
}
line[length - 1] = 0;
- if (do_command(line)) {
- fprintf(stderr, "bad command: %s\n", line);
+ command = line;
+ }
+ if (pollfd[1].revents & POLLOUT) {
+ if (do_command(command)) {
+ fprintf(stderr, "bad command: %s\n", command);
}
+ command = NULL;
}
if (pollfd[1].revents & (POLLIN|POLLPRI)) {
msg = pmc_recv(pmc);
--
1.7.11.7
Keller, Jacob E
2013-02-05 20:45:04 UTC
Permalink
Wouldn't it be possible to just use redirecton to make stdin a file?

Not sure which is easier but I suppose supporting command line format would be useful too.
-----Original Message-----
Sent: Tuesday, February 05, 2013 8:36 AM
Subject: [Linuxptp-devel] [PATCH 03/13] pmc: Allow commands on
command line.
Add a batch mode, where the commands are taken from the command line
instead of the standard input.
---
pmc.8 | 8 ++++----
pmc.c | 39 +++++++++++++++++++++++++++++++--------
2 files changed, 35 insertions(+), 12 deletions(-)
diff --git a/pmc.8 b/pmc.8
index dfe71bb..1128bf7 100644
--- a/pmc.8
+++ b/pmc.8
@@ -22,14 +22,14 @@ pmc \- PTP management client
.BI \-t " transport-specific-field"
] [
.B \-v
-]
+] [ command ] ...
.SH DESCRIPTION
.B pmc
is a program which implements a PTP management client according to IEEE
-standard 1588. The program reads from the standard input actions specified by
-name and management ID, sends them over the selected transport and prints any
+standard 1588. The program reads from the standard input or from the command
+line actions specified by name and management ID, sends them over the selected
.B GET
retrieves the specified information,
.B SET
diff --git a/pmc.c b/pmc.c
index 2736d85..5e000bb 100644
--- a/pmc.c
+++ b/pmc.c
@@ -381,7 +381,7 @@ static int do_command(char *str)
static void usage(char *progname)
{
fprintf(stderr,
- "\nusage: %s [options]\n\n"
+ "\nusage: %s [options] [commands]\n\n"
" Network Transport\n\n"
" -2 IEEE 802.3\n"
" -4 UDP IPV4 (default)\n"
@@ -402,8 +402,8 @@ static void usage(char *progname)
int main(int argc, char *argv[])
{
char *iface_name = NULL, *progname;
- int c, cnt, length, tmo = -1;
- char line[1024];
+ int c, cnt, length, tmo = -1, batch_mode = 0;
+ char line[1024], *command = NULL;
enum transport_type transport_type = TRANS_UDP_IPV4;
UInteger8 boundary_hops = 1, domain_number = 0,
transport_specific = 0;
struct ptp_message *msg;
@@ -458,6 +458,9 @@ int main(int argc, char *argv[])
if (!iface_name) {
iface_name = transport_type == TRANS_UDS ?
"/var/run/pmc" : "eth0";
}
+ if (optind < argc) {
+ batch_mode = 1;
+ }
print_set_progname(progname);
print_set_syslog(1);
@@ -469,12 +472,28 @@ int main(int argc, char *argv[])
return -1;
}
- pollfd[0].fd = STDIN_FILENO;
- pollfd[0].events = POLLIN|POLLPRI;
+ pollfd[0].fd = batch_mode ? -1 : STDIN_FILENO;
pollfd[1].fd = pmc_get_transport_fd(pmc);
- pollfd[1].events = POLLIN|POLLPRI;
while (1) {
+ if (batch_mode && !command) {
+ if (optind < argc) {
+ command = argv[optind++];
+ } else {
+ /* No more commands, wait a bit for
+ any outstanding replies and exit. */
+ tmo = 100;
+ }
+ }
+
+ pollfd[0].events = 0;
+ pollfd[1].events = POLLIN | POLLPRI;
+
+ if (!batch_mode && !command)
+ pollfd[0].events |= POLLIN | POLLPRI;
+ if (command)
+ pollfd[1].events |= POLLOUT;
+
cnt = poll(pollfd, N_FD, tmo);
if (cnt < 0) {
if (EINTR == errno) {
@@ -505,9 +524,13 @@ int main(int argc, char *argv[])
continue;
}
line[length - 1] = 0;
- if (do_command(line)) {
- fprintf(stderr, "bad command: %s\n",
line);
+ command = line;
+ }
+ if (pollfd[1].revents & POLLOUT) {
+ if (do_command(command)) {
+ fprintf(stderr, "bad command: %s\n",
command);
}
+ command = NULL;
}
if (pollfd[1].revents & (POLLIN|POLLPRI)) {
msg = pmc_recv(pmc);
--
1.7.11.7
------------------------------------------------------------------------------
Free Next-Gen Firewall Hardware Offer
Buy your Sophos next-gen firewall before the end March 2013
and get the hardware for free! Learn more.
http://p.sf.net/sfu/sophos-d2d-feb
_______________________________________________
Linuxptp-devel mailing list
https://lists.sourceforge.net/lists/listinfo/linuxptp-devel
Richard Cochran
2013-02-06 07:31:51 UTC
Permalink
Post by Keller, Jacob E
Wouldn't it be possible to just use redirecton to make stdin a file?
Yep. Here is a poor man's management monitor that works just that way:

---8<---
#!/bin/bash

while [ 1 ]; do
clear
printf "get cur\n" | ./pmc
sleep 1
done

# Local host and network query:
# printf "get cur\n" | ./pmc -u
# get cur
# get par
# get time_p
# get time_s
# get port
---8<---
Post by Keller, Jacob E
Not sure which is easier but I suppose supporting command line format would be useful too.
I also think that batch commands on the command line are a nice
addition.

Thanks,
Richard
Miroslav Lichvar
2013-02-05 16:36:04 UTC
Permalink
Signed-off-by: Miroslav Lichvar <***@redhat.com>
---
phc2sys.8 | 6 ++++++
phc2sys.c | 6 +++++-
2 files changed, 11 insertions(+), 1 deletion(-)

diff --git a/phc2sys.8 b/phc2sys.8
index e26641a..58d0b49 100644
--- a/phc2sys.8
+++ b/phc2sys.8
@@ -81,6 +81,12 @@ Specify the proportional constant of the PI controller. The default is 0.7.
.BI \-I " ki"
Specify the integral constant of the PI controller. The default is 0.3.
.TP
+.BI \-S " step"
+Specify the step threshold of the PI controller. It is the maximum offset that
+the controller corrects by changing the clock frequency instead of stepping the
+clock. The clock is always stepped on start. The value of 0.0 disables stepping
+after the start. The default is 0.0.
+.TP
.BI \-R " update-rate"
Specify the slave clock update rate when running in the direct synchronization
mode. The default is 1 per second.
diff --git a/phc2sys.c b/phc2sys.c
index 17d00db..3d0f009 100644
--- a/phc2sys.c
+++ b/phc2sys.c
@@ -421,6 +421,7 @@ static void usage(char *progname)
" -i [iface] master clock by network interface\n"
" -P [kp] proportional constant (0.7)\n"
" -I [ki] integration constant (0.3)\n"
+ " -S [step] step threshold (disabled)\n"
" -R [rate] slave clock update rate in HZ (1)\n"
" -N [num] number of master clock readings per update (5)\n"
" -O [offset] slave-master time offset (0)\n"
@@ -449,7 +450,7 @@ int main(int argc, char *argv[])
/* Process the command line arguments. */
progname = strrchr(argv[0], '/');
progname = progname ? 1+progname : argv[0];
- while (EOF != (c = getopt(argc, argv, "c:d:hs:P:I:R:N:O:i:wv"))) {
+ while (EOF != (c = getopt(argc, argv, "c:d:hs:P:I:S:R:N:O:i:wv"))) {
switch (c) {
case 'c':
dst_clock.clkid = clock_open(optarg);
@@ -466,6 +467,9 @@ int main(int argc, char *argv[])
case 'I':
configured_pi_ki = atof(optarg);
break;
+ case 'S':
+ configured_pi_offset = atof(optarg);
+ break;
case 'R':
phc_rate = atoi(optarg);
break;
--
1.7.11.7
Miroslav Lichvar
2013-02-05 16:36:08 UTC
Permalink
Use pr_* functions to print messages and add -m, -q, -l options to allow
configuration of the printing level and where should be the messages sent.

Signed-off-by: Miroslav Lichvar <***@redhat.com>
---
phc2sys.8 | 16 ++++++++++++++++
phc2sys.c | 46 ++++++++++++++++++++++++++--------------------
2 files changed, 42 insertions(+), 20 deletions(-)

diff --git a/phc2sys.8 b/phc2sys.8
index 58d0b49..c08952a 100644
--- a/phc2sys.8
+++ b/phc2sys.8
@@ -29,6 +29,12 @@ phc2sys \- synchronize two clocks
] [
.B \-w
] [
+.BI \-l " print-level"
+] [
+.B \-m
+] [
+.B \-q
+] [
.B \-v
]

@@ -109,6 +115,16 @@ the default is 0.
.B \-w
Wait until ptp4l is in a synchronized state.
.TP
+.BI \-l " print-level"
+Set the maximum syslog level of messages which should be printed or sent to
+the system logger. The default is 6 (LOG_INFO).
+.TP
+.B \-m
+Print messages to the standard output.
+.TP
+.B \-q
+Don't send messages to the system logger.
+.TP
.BI \-h
Display a help message.
.TP
diff --git a/phc2sys.c b/phc2sys.c
index 6c07186..b6044ef 100644
--- a/phc2sys.c
+++ b/phc2sys.c
@@ -81,7 +81,7 @@ static void clock_ppb(clockid_t clkid, double ppb)
tx.modes = ADJ_FREQUENCY;
tx.freq = (long) (ppb * 65.536);
if (clock_adjtime(clkid, &tx) < 0)
- fprintf(stderr, "failed to adjust the clock: %m\n");
+ pr_err("failed to adjust the clock: %m");
}

static double clock_ppb_read(clockid_t clkid)
@@ -90,7 +90,7 @@ static double clock_ppb_read(clockid_t clkid)
struct timex tx;
memset(&tx, 0, sizeof(tx));
if (clock_adjtime(clkid, &tx) < 0)
- fprintf(stderr, "failed to read out the clock frequency adjustment: %m\n");
+ pr_err("failed to read out the clock frequency adjustment: %m");
else
f = tx.freq / 65.536;
return f;
@@ -117,7 +117,7 @@ static void clock_step(clockid_t clkid, int64_t ns)
tx.time.tv_usec += 1000000000;
}
if (clock_adjtime(clkid, &tx) < 0)
- fprintf(stderr, "failed to step clock: %m\n");
+ pr_err("failed to step clock: %m");
}

static int read_phc(clockid_t clkid, clockid_t sysclk, int readings,
@@ -132,7 +132,7 @@ static int read_phc(clockid_t clkid, clockid_t sysclk, int readings,
if (clock_gettime(sysclk, &tdst1) ||
clock_gettime(clkid, &tsrc) ||
clock_gettime(sysclk, &tdst2)) {
- perror("clock_gettime");
+ pr_err("failed to read clock: %m");
return 0;
}

@@ -153,7 +153,6 @@ static int read_phc(clockid_t clkid, clockid_t sysclk, int readings,
struct clock {
clockid_t clkid;
struct servo *servo;
- FILE *log_file;
const char *source_label;
};

@@ -175,10 +174,9 @@ static void update_clock(struct clock *clock, int64_t offset, uint64_t ts)
break;
}

- fprintf(clock->log_file, "%s %9" PRId64 " s%d %lld.%09llu adj %.2f\n",
+ pr_info("%s %9" PRId64 " s%d %lld.%09llu adj %.2f",
clock->source_label, offset, state,
ts / NS_PER_SEC, ts % NS_PER_SEC, ppb);
- fflush(clock->log_file);
}

static int read_pps(int fd, int64_t *offset, uint64_t *ts)
@@ -189,7 +187,7 @@ static int read_pps(int fd, int64_t *offset, uint64_t *ts)
pfd.timeout.nsec = 0;
pfd.timeout.flags = ~PPS_TIME_INVALID;
if (ioctl(fd, PPS_FETCH, &pfd)) {
- perror("ioctl PPS_FETCH");
+ pr_err("failed to fetch PPS: %m");
return 0;
}

@@ -228,8 +226,8 @@ static int do_pps_loop(struct clock *clock, int fd,

/* Check if it is close to the start of the second. */
if (phc_ts % NS_PER_SEC > PHC_PPS_OFFSET_LIMIT) {
- fprintf(stderr, "PPS is not in sync with PHC"
- " (0.%09lld)\n", phc_ts % NS_PER_SEC);
+ pr_warning("PPS is not in sync with PHC"
+ " (0.%09lld)", phc_ts % NS_PER_SEC);
continue;
}

@@ -326,7 +324,7 @@ static int run_pmc(int wait_sync, int *utc_offset)

pmc = pmc_create(TRANS_UDS, "/var/run/phc2sys", 0, 0, 0);
if (!pmc) {
- fprintf(stderr, "failed to create pmc\n");
+ pr_err("failed to create pmc");
return -1;
}

@@ -338,13 +336,13 @@ static int run_pmc(int wait_sync, int *utc_offset)

cnt = poll(pollfd, N_FD, 1000);
if (cnt < 0) {
- fprintf(stderr, "poll failed\n");
+ pr_err("poll failed");
return -1;
}
if (!cnt) {
/* Request the data set again. */
ds_requested = 0;
- fprintf(stderr, "Waiting for ptp4l...\n");
+ pr_notice("Waiting for ptp4l...");
continue;
}

@@ -431,11 +429,9 @@ int main(int argc, char *argv[])
clockid_t src = CLOCK_INVALID;
int c, phc_readings = 5, phc_rate = 1, sync_offset = 0, pps_fd = -1;
int wait_sync = 0, forced_sync_offset = 0;
+ int print_level = LOG_INFO, use_syslog = 1, verbose = 0;
double ppb;
- struct clock dst_clock = {
- .clkid = CLOCK_REALTIME,
- .log_file = stdout
- };
+ struct clock dst_clock = { .clkid = CLOCK_REALTIME };

configured_pi_kp = KP;
configured_pi_ki = KI;
@@ -443,7 +439,7 @@ int main(int argc, char *argv[])
/* Process the command line arguments. */
progname = strrchr(argv[0], '/');
progname = progname ? 1+progname : argv[0];
- while (EOF != (c = getopt(argc, argv, "c:d:hs:P:I:S:R:N:O:i:wv"))) {
+ while (EOF != (c = getopt(argc, argv, "c:d:hs:P:I:S:R:N:O:i:wl:mqv"))) {
switch (c) {
case 'c':
dst_clock.clkid = clock_open(optarg);
@@ -484,6 +480,15 @@ int main(int argc, char *argv[])
case 'w':
wait_sync = 1;
break;
+ case 'l':
+ print_level = atoi(optarg);
+ break;
+ case 'm':
+ verbose = 1;
+ break;
+ case 'q':
+ use_syslog = 0;
+ break;
case 'v':
version_show(stdout);
return 0;
@@ -518,8 +523,9 @@ int main(int argc, char *argv[])
}

print_set_progname(progname);
- print_set_verbose(1);
- print_set_syslog(0);
+ print_set_verbose(verbose);
+ print_set_syslog(use_syslog);
+ print_set_level(print_level);

if (wait_sync) {
int ptp_utc_offset;
--
1.7.11.7
Miroslav Lichvar
2013-02-05 16:36:09 UTC
Permalink
Signed-off-by: Miroslav Lichvar <***@redhat.com>
---
print.c | 6 ++++--
1 file changed, 4 insertions(+), 2 deletions(-)

diff --git a/print.c b/print.c
index 7c21902..a82d0e7 100644
--- a/print.c
+++ b/print.c
@@ -54,6 +54,7 @@ void print(int level, char const *format, ...)
struct timespec ts;
va_list ap;
char buf[1024];
+ FILE *f;

if (level > print_level)
return;
@@ -65,10 +66,11 @@ void print(int level, char const *format, ...)
va_end(ap);

if (verbose) {
- fprintf(stdout, "%s[%ld.%03ld]: %s\n",
+ f = level >= LOG_NOTICE ? stdout : stderr;
+ fprintf(f, "%s[%ld.%03ld]: %s\n",
progname ? progname : "",
ts.tv_sec, ts.tv_nsec / 1000000, buf);
- fflush(stdout);
+ fflush(f);
}
if (use_syslog) {
syslog(level, "[%ld.%03ld] %s",
--
1.7.11.7
Miroslav Lichvar
2013-02-05 16:36:07 UTC
Permalink
Possible error messages should be printed before waiting on ptp4l.

Signed-off-by: Miroslav Lichvar <***@redhat.com>
---
phc2sys.c | 28 +++++++++++++---------------
1 file changed, 13 insertions(+), 15 deletions(-)

diff --git a/phc2sys.c b/phc2sys.c
index 8fddfa9..6c07186 100644
--- a/phc2sys.c
+++ b/phc2sys.c
@@ -203,21 +203,14 @@ static int read_pps(int fd, int64_t *offset, uint64_t *ts)
return 1;
}

-static int do_pps_loop(struct clock *clock, char *pps_device,
+static int do_pps_loop(struct clock *clock, int fd,
clockid_t src, int n_readings, int sync_offset)
{
int64_t pps_offset, phc_offset;
uint64_t pps_ts, phc_ts;
- int fd;

clock->source_label = "pps";

- fd = open(pps_device, O_RDONLY);
- if (fd < 0) {
- fprintf(stderr, "cannot open '%s': %m\n", pps_device);
- return -1;
- }
-
while (1) {
if (!read_pps(fd, &pps_offset, &pps_ts)) {
continue;
@@ -434,9 +427,9 @@ static void usage(char *progname)

int main(int argc, char *argv[])
{
- char *device = NULL, *progname, *ethdev = NULL;
+ char *progname, *ethdev = NULL;
clockid_t src = CLOCK_INVALID;
- int c, phc_readings = 5, phc_rate = 1, sync_offset = 0;
+ int c, phc_readings = 5, phc_rate = 1, sync_offset = 0, pps_fd = -1;
int wait_sync = 0, forced_sync_offset = 0;
double ppb;
struct clock dst_clock = {
@@ -456,7 +449,12 @@ int main(int argc, char *argv[])
dst_clock.clkid = clock_open(optarg);
break;
case 'd':
- device = optarg;
+ pps_fd = open(optarg, O_RDONLY);
+ if (pps_fd < 0) {
+ fprintf(stderr,
+ "cannot open '%s': %m\n", optarg);
+ return -1;
+ }
break;
case 's':
src = clock_open(optarg);
@@ -512,9 +510,9 @@ int main(int argc, char *argv[])
sprintf(phc_device, "/dev/ptp%d", ts_info.phc_index);
src = clock_open(phc_device);
}
- if (!(device || src != CLOCK_INVALID) ||
+ if (!(pps_fd >= 0 || src != CLOCK_INVALID) ||
dst_clock.clkid == CLOCK_INVALID ||
- (device && dst_clock.clkid != CLOCK_REALTIME)) {
+ (pps_fd >= 0 && dst_clock.clkid != CLOCK_REALTIME)) {
usage(progname);
return -1;
}
@@ -545,8 +543,8 @@ int main(int argc, char *argv[])

dst_clock.servo = servo_create(CLOCK_SERVO_PI, -ppb, max_ppb, 0);

- if (device)
- return do_pps_loop(&dst_clock, device, src,
+ if (pps_fd >= 0)
+ return do_pps_loop(&dst_clock, pps_fd, src,
phc_readings, sync_offset);

if (dst_clock.clkid == CLOCK_REALTIME &&
--
1.7.11.7
Miroslav Lichvar
2013-02-05 16:36:10 UTC
Permalink
Before calculating the clock drift in the PI servo, make sure
the first sample is older than the second sample to avoid getting
invalid drift or NaN.

Signed-off-by: Miroslav Lichvar <***@redhat.com>
---
pi.c | 6 ++++++
1 file changed, 6 insertions(+)

diff --git a/pi.c b/pi.c
index 825ec22..c3a4035 100644
--- a/pi.c
+++ b/pi.c
@@ -73,6 +73,12 @@ static double pi_sample(struct servo *servo,
s->offset[1] = offset;
s->local[1] = local_ts;

+ /* Make sure the first sample is older than the second. */
+ if (s->local[0] >= s->local[1]) {
+ s->count = 0;
+ break;
+ }
+
s->drift += (s->offset[1] - s->offset[0]) * 1e9 /
(s->local[1] - s->local[0]);
if (s->drift < -s->maxppb)
--
1.7.11.7
Miroslav Lichvar
2013-02-05 16:36:11 UTC
Permalink
This was missed in commit d8cb9be46a225a159168581531d401fa2eff8c68.

Signed-off-by: Miroslav Lichvar <***@redhat.com>
---
pi.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/pi.c b/pi.c
index c3a4035..ec7e456 100644
--- a/pi.c
+++ b/pi.c
@@ -94,7 +94,7 @@ static double pi_sample(struct servo *servo,
/*
* reset the clock servo when offset is greater than the max
* offset value. Note that the clock jump will be performed in
- * step 3, so it is not necessary to have clock jump
+ * step 1, so it is not necessary to have clock jump
* immediately. This allows re-calculating drift as in initial
* clock startup.
*/
--
1.7.11.7
Miroslav Lichvar
2013-02-05 16:36:12 UTC
Permalink
Signed-off-by: Miroslav Lichvar <***@redhat.com>
---
hwstamp_ctl.8 | 2 +-
phc2sys.8 | 4 ++--
phc2sys.c | 2 +-
3 files changed, 4 insertions(+), 4 deletions(-)

diff --git a/hwstamp_ctl.8 b/hwstamp_ctl.8
index e65071d..cece74f 100644
--- a/hwstamp_ctl.8
+++ b/hwstamp_ctl.8
@@ -19,7 +19,7 @@ is a program used to set the hardware time stamping policy at the network
driver level with the
.B SIOCSHWTSTAMP
.BR ioctl (2).
-The
+The
.I tx-type
and
.I rx-filter
diff --git a/phc2sys.8 b/phc2sys.8
index c08952a..578d4ab 100644
--- a/phc2sys.8
+++ b/phc2sys.8
@@ -63,7 +63,7 @@ should be already close to the correct time before
is started or the
.B \-s
option should be used too. This option can be used only with the system clock as
-the slave clock.
+the slave clock.
.TP
.BI \-s " phc-device"
Specify the master clock by device (e.g. /dev/ptp0) or name (e.g. CLOCK_REALTIME
@@ -75,7 +75,7 @@ seconds, which cannot be fixed with PPS alone.
.BI \-i " interface"
Similar to the
.B \-s
-option, but specified by the interface which provides the master clock.
+option, but specified by the interface which provides the master clock.
.TP
.BI \-c " phc-device"
Specify the slave clock by device (e.g. /dev/ptp1) or name. The default is
diff --git a/phc2sys.c b/phc2sys.c
index b6044ef..cd1a505 100644
--- a/phc2sys.c
+++ b/phc2sys.c
@@ -220,7 +220,7 @@ static int do_pps_loop(struct clock *clock, int fd,
if (!read_phc(src, clock->clkid, n_readings,
&phc_offset, &phc_ts))
return -1;
-
+
/* Convert the time stamp to the PHC time. */
phc_ts -= phc_offset;
--
1.7.11.7
Miroslav Lichvar
2013-02-05 16:36:13 UTC
Permalink
Call clock_sync_interval with every sync message. This seems to be needed
to know the correct clock sync interval even when logSyncInterval
doesn't change from 0 and perhaps also when the clock sync switches
between ports with different logSyncInterval.

Signed-off-by: Miroslav Lichvar <***@redhat.com>
---
port.c | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/port.c b/port.c
index 6c9bd32..bd64c62 100644
--- a/port.c
+++ b/port.c
@@ -1397,9 +1397,10 @@ static void process_sync(struct port *p, struct ptp_message *m)

if (m->header.logMessageInterval != p->log_sync_interval) {
p->log_sync_interval = m->header.logMessageInterval;
- clock_sync_interval(p->clock, p->log_sync_interval);
}

+ clock_sync_interval(p->clock, p->log_sync_interval);
+
m->header.correction += p->pod.asymmetry;

if (one_step(m)) {
--
1.7.11.7
Richard Cochran
2013-02-06 19:08:59 UTC
Permalink
Post by Miroslav Lichvar
Call clock_sync_interval with every sync message. This seems to be needed
to know the correct clock sync interval even when logSyncInterval
doesn't change from 0 and perhaps also when the clock sync switches
between ports with different logSyncInterval.
Can you explain why this is needed?

I don't see the problem. I guess this fix is related to trouble you
had with the stats mode in the following patch.

Thanks,
Richard
Miroslav Lichvar
2013-02-05 16:36:14 UTC
Permalink
Change the label of the frequency offset in the clock messages printed
in ptp4l and phc2sys from "adj" to "freq" to indicate it's a frequency
adjustment.

Also, change clock_no_adjust() to print the frequency offset instead of
the ratio and use PRId64 instead of lld to print int64_t values.

Signed-off-by: Miroslav Lichvar <***@redhat.com>
---
clock.c | 11 +++++++----
phc2sys.c | 2 +-
2 files changed, 8 insertions(+), 5 deletions(-)

diff --git a/clock.c b/clock.c
index 98e91d3..413963c 100644
--- a/clock.c
+++ b/clock.c
@@ -217,7 +217,7 @@ static int clock_master_lost(struct clock *c)
static enum servo_state clock_no_adjust(struct clock *c)
{
double fui;
- double ratio;
+ double ratio, freq;
tmv_t origin2;
struct freq_estimator *f = &c->fest;
enum servo_state state = SERVO_UNLOCKED;
@@ -258,9 +258,11 @@ static enum servo_state clock_no_adjust(struct clock *c)

ratio = tmv_dbl(tmv_sub(origin2, f->origin1)) /
tmv_dbl(tmv_sub(c->t2, f->ingress1));
+ freq = (1.0 - ratio) * 1e9;

- pr_info("master offset %10lld s%d ratio %.9f path delay %10lld",
- c->master_offset, state, ratio, c->path_delay);
+ pr_info("master offset %10" PRId64 " s%d freq %+7.0f "
+ "path delay %9" PRId64,
+ c->master_offset, state, freq, c->path_delay);

fui = 1.0 + (c->status.cumulativeScaledRateOffset + 0.0) / POW2_41;

@@ -862,7 +864,8 @@ enum servo_state clock_synchronize(struct clock *c,

adj = servo_sample(c->servo, c->master_offset, ingress, &state);

- pr_info("master offset %10lld s%d adj %+7.0f path delay %10lld",
+ pr_info("master offset %10" PRId64 " s%d freq %+7.0f "
+ "path delay %9" PRId64,
c->master_offset, state, adj, c->path_delay);

switch (state) {
diff --git a/phc2sys.c b/phc2sys.c
index cd1a505..6b93e42 100644
--- a/phc2sys.c
+++ b/phc2sys.c
@@ -174,7 +174,7 @@ static void update_clock(struct clock *clock, int64_t offset, uint64_t ts)
break;
}

- pr_info("%s %9" PRId64 " s%d %lld.%09llu adj %.2f",
+ pr_info("%s %9" PRId64 " s%d %lld.%09llu freq %+7.0f",
clock->source_label, offset, state,
ts / NS_PER_SEC, ts % NS_PER_SEC, ppb);
}
--
1.7.11.7
Richard Cochran
2013-02-06 19:13:07 UTC
Permalink
Post by Miroslav Lichvar
Also, change clock_no_adjust() to print the frequency offset instead of
the ratio and use PRId64 instead of lld to print int64_t values.
The clock_no_adjust function was introduced primarily to support
802.1AS which always is taking about the ratios. I don't have a strong
feeling about switching the printout to frequency, but maybe one of
the gPTP users does?

Thanks,
Richard
Miroslav Lichvar
2013-02-07 12:27:11 UTC
Permalink
Post by Richard Cochran
Post by Miroslav Lichvar
Also, change clock_no_adjust() to print the frequency offset instead of
the ratio and use PRId64 instead of lld to print int64_t values.
The clock_no_adjust function was introduced primarily to support
802.1AS which always is taking about the ratios. I don't have a strong
feeling about switching the printout to frequency, but maybe one of
the gPTP users does?
I don't feel strongly about it, I just wanted to avoid duplicating the
stats update and printing code for ratio. I'm open to suggestions.

Thanks,
--
Miroslav Lichvar
Miroslav Lichvar
2013-02-05 16:36:15 UTC
Permalink
If the delay is known, print it together with the offset and frequency.
Remove the time stamp from the output to fit it into 80 chars.

Signed-off-by: Miroslav Lichvar <***@redhat.com>
---
phc2sys.c | 36 ++++++++++++++++++++++--------------
sysoff.c | 12 ++++++++----
sysoff.h | 4 +++-
3 files changed, 33 insertions(+), 19 deletions(-)

diff --git a/phc2sys.c b/phc2sys.c
index 6b93e42..c33daea 100644
--- a/phc2sys.c
+++ b/phc2sys.c
@@ -121,7 +121,7 @@ static void clock_step(clockid_t clkid, int64_t ns)
}

static int read_phc(clockid_t clkid, clockid_t sysclk, int readings,
- int64_t *offset, uint64_t *ts)
+ int64_t *offset, uint64_t *ts, int64_t *delay)
{
struct timespec tdst1, tdst2, tsrc;
int i;
@@ -146,6 +146,7 @@ static int read_phc(clockid_t clkid, clockid_t sysclk, int readings,
*ts = tdst2.tv_sec * NS_PER_SEC + tdst2.tv_nsec;
}
}
+ *delay = best_interval;

return 1;
}
@@ -156,7 +157,8 @@ struct clock {
const char *source_label;
};

-static void update_clock(struct clock *clock, int64_t offset, uint64_t ts)
+static void update_clock(struct clock *clock,
+ int64_t offset, uint64_t ts, int64_t delay)
{
enum servo_state state;
double ppb;
@@ -174,9 +176,14 @@ static void update_clock(struct clock *clock, int64_t offset, uint64_t ts)
break;
}

- pr_info("%s %9" PRId64 " s%d %lld.%09llu freq %+7.0f",
- clock->source_label, offset, state,
- ts / NS_PER_SEC, ts % NS_PER_SEC, ppb);
+ if (delay >= 0) {
+ pr_info("%s offset %9" PRId64 " s%d freq %+7.0f "
+ "delay %6" PRId64,
+ clock->source_label, offset, state, ppb, delay);
+ } else {
+ pr_info("%s offset %9" PRId64 " s%d freq %+7.0f",
+ clock->source_label, offset, state, ppb);
+ }
}

static int read_pps(int fd, int64_t *offset, uint64_t *ts)
@@ -204,7 +211,7 @@ static int read_pps(int fd, int64_t *offset, uint64_t *ts)
static int do_pps_loop(struct clock *clock, int fd,
clockid_t src, int n_readings, int sync_offset)
{
- int64_t pps_offset, phc_offset;
+ int64_t pps_offset, phc_offset, phc_delay;
uint64_t pps_ts, phc_ts;

clock->source_label = "pps";
@@ -218,7 +225,7 @@ static int do_pps_loop(struct clock *clock, int fd,
of seconds in the offset and PPS for the rest. */
if (src != CLOCK_INVALID) {
if (!read_phc(src, clock->clkid, n_readings,
- &phc_offset, &phc_ts))
+ &phc_offset, &phc_ts, &phc_delay))
return -1;

/* Convert the time stamp to the PHC time. */
@@ -236,7 +243,7 @@ static int do_pps_loop(struct clock *clock, int fd,
pps_offset -= sync_offset * NS_PER_SEC;
}

- update_clock(clock, pps_offset, pps_ts);
+ update_clock(clock, pps_offset, pps_ts, -1);
}
close(fd);
return 0;
@@ -246,19 +253,19 @@ static int do_sysoff_loop(struct clock *clock, clockid_t src,
int rate, int n_readings, int sync_offset)
{
uint64_t ts;
- int64_t offset;
+ int64_t offset, delay;
int err = 0, fd = CLOCKID_TO_FD(src);

clock->source_label = "sys";

while (1) {
usleep(1000000 / rate);
- if (sysoff_measure(fd, n_readings, &offset, &ts)) {
+ if (sysoff_measure(fd, n_readings, &offset, &ts, &delay)) {
err = -1;
break;
}
offset -= sync_offset * NS_PER_SEC;
- update_clock(clock, offset, ts);
+ update_clock(clock, offset, ts, delay);
}
return err;
}
@@ -267,17 +274,18 @@ static int do_phc_loop(struct clock *clock, clockid_t src,
int rate, int n_readings, int sync_offset)
{
uint64_t ts;
- int64_t offset;
+ int64_t offset, delay;

clock->source_label = "phc";

while (1) {
usleep(1000000 / rate);
- if (!read_phc(src, clock->clkid, n_readings, &offset, &ts)) {
+ if (!read_phc(src, clock->clkid, n_readings,
+ &offset, &ts, &delay)) {
continue;
}
offset -= sync_offset * NS_PER_SEC;
- update_clock(clock, offset, ts);
+ update_clock(clock, offset, ts, delay);
}
return 0;
}
diff --git a/sysoff.c b/sysoff.c
index 37a9664..895566c 100644
--- a/sysoff.c
+++ b/sysoff.c
@@ -52,7 +52,8 @@ static void insertion_sort(int length, int64_t interval, int64_t offset, uint64_
samples[i+1].timestamp = ts;
}

-static int64_t sysoff_estimate(struct ptp_clock_time *pct, int n_samples, uint64_t *ts)
+static int64_t sysoff_estimate(struct ptp_clock_time *pct, int n_samples,
+ uint64_t *ts, int64_t *delay)
{
int64_t t1, t2, tp;
int64_t interval, offset;
@@ -67,10 +68,12 @@ static int64_t sysoff_estimate(struct ptp_clock_time *pct, int n_samples, uint64
insertion_sort(i, interval, offset, (t2 + t1) / 2);
}
*ts = samples[0].timestamp;
+ *delay = samples[0].interval;
return samples[0].offset;
}

-int sysoff_measure(int fd, int n_samples, int64_t *result, uint64_t *ts)
+int sysoff_measure(int fd, int n_samples,
+ int64_t *result, uint64_t *ts, int64_t *delay)
{
struct ptp_sys_offset pso;
pso.n_samples = n_samples;
@@ -78,7 +81,7 @@ int sysoff_measure(int fd, int n_samples, int64_t *result, uint64_t *ts)
perror("ioctl PTP_SYS_OFFSET");
return SYSOFF_RUN_TIME_MISSING;
}
- *result = sysoff_estimate(pso.ts, n_samples, ts);
+ *result = sysoff_estimate(pso.ts, n_samples, ts, delay);
return SYSOFF_SUPPORTED;
}

@@ -99,7 +102,8 @@ int sysoff_probe(int fd, int n_samples)

#else /* !PTP_SYS_OFFSET */

-int sysoff_measure(int fd, int n_samples, int64_t *result, uint64_t *ts)
+int sysoff_measure(int fd, int n_samples,
+ int64_t *result, uint64_t *ts, int64_t *delay)
{
return SYSOFF_COMPILE_TIME_MISSING;
}
diff --git a/sysoff.h b/sysoff.h
index f2e481e..cb70265 100644
--- a/sysoff.h
+++ b/sysoff.h
@@ -39,6 +39,8 @@ int sysoff_probe(int fd, int n_samples);
* @param n_samples The number of consecutive readings to make.
* @param result The estimated offset in nanoseconds.
* @param ts The system time corresponding to the 'result'.
+ * @param delay The delay in reading of the clock in nanoseconds.
* @return One of the SYSOFF_ enumeration values.
*/
-int sysoff_measure(int fd, int n_samples, int64_t *result, uint64_t *ts);
+int sysoff_measure(int fd, int n_samples,
+ int64_t *result, uint64_t *ts, int64_t *delay);
--
1.7.11.7
Miroslav Lichvar
2013-02-05 18:30:08 UTC
Permalink
If the delay is known, print it together with the offset and frequency.
Remove the time stamp from the output to fit it into 80 chars.

Signed-off-by: Miroslav Lichvar <***@redhat.com>
---
phc2sys.c | 36 ++++++++++++++++++++++--------------
sysoff.c | 16 ++++++++++------
sysoff.h | 4 +++-
3 files changed, 35 insertions(+), 21 deletions(-)

diff --git a/phc2sys.c b/phc2sys.c
index 6b93e42..c33daea 100644
--- a/phc2sys.c
+++ b/phc2sys.c
@@ -121,7 +121,7 @@ static void clock_step(clockid_t clkid, int64_t ns)
}

static int read_phc(clockid_t clkid, clockid_t sysclk, int readings,
- int64_t *offset, uint64_t *ts)
+ int64_t *offset, uint64_t *ts, int64_t *delay)
{
struct timespec tdst1, tdst2, tsrc;
int i;
@@ -146,6 +146,7 @@ static int read_phc(clockid_t clkid, clockid_t sysclk, int readings,
*ts = tdst2.tv_sec * NS_PER_SEC + tdst2.tv_nsec;
}
}
+ *delay = best_interval;

return 1;
}
@@ -156,7 +157,8 @@ struct clock {
const char *source_label;
};

-static void update_clock(struct clock *clock, int64_t offset, uint64_t ts)
+static void update_clock(struct clock *clock,
+ int64_t offset, uint64_t ts, int64_t delay)
{
enum servo_state state;
double ppb;
@@ -174,9 +176,14 @@ static void update_clock(struct clock *clock, int64_t offset, uint64_t ts)
break;
}

- pr_info("%s %9" PRId64 " s%d %lld.%09llu freq %+7.0f",
- clock->source_label, offset, state,
- ts / NS_PER_SEC, ts % NS_PER_SEC, ppb);
+ if (delay >= 0) {
+ pr_info("%s offset %9" PRId64 " s%d freq %+7.0f "
+ "delay %6" PRId64,
+ clock->source_label, offset, state, ppb, delay);
+ } else {
+ pr_info("%s offset %9" PRId64 " s%d freq %+7.0f",
+ clock->source_label, offset, state, ppb);
+ }
}

static int read_pps(int fd, int64_t *offset, uint64_t *ts)
@@ -204,7 +211,7 @@ static int read_pps(int fd, int64_t *offset, uint64_t *ts)
static int do_pps_loop(struct clock *clock, int fd,
clockid_t src, int n_readings, int sync_offset)
{
- int64_t pps_offset, phc_offset;
+ int64_t pps_offset, phc_offset, phc_delay;
uint64_t pps_ts, phc_ts;

clock->source_label = "pps";
@@ -218,7 +225,7 @@ static int do_pps_loop(struct clock *clock, int fd,
of seconds in the offset and PPS for the rest. */
if (src != CLOCK_INVALID) {
if (!read_phc(src, clock->clkid, n_readings,
- &phc_offset, &phc_ts))
+ &phc_offset, &phc_ts, &phc_delay))
return -1;

/* Convert the time stamp to the PHC time. */
@@ -236,7 +243,7 @@ static int do_pps_loop(struct clock *clock, int fd,
pps_offset -= sync_offset * NS_PER_SEC;
}

- update_clock(clock, pps_offset, pps_ts);
+ update_clock(clock, pps_offset, pps_ts, -1);
}
close(fd);
return 0;
@@ -246,19 +253,19 @@ static int do_sysoff_loop(struct clock *clock, clockid_t src,
int rate, int n_readings, int sync_offset)
{
uint64_t ts;
- int64_t offset;
+ int64_t offset, delay;
int err = 0, fd = CLOCKID_TO_FD(src);

clock->source_label = "sys";

while (1) {
usleep(1000000 / rate);
- if (sysoff_measure(fd, n_readings, &offset, &ts)) {
+ if (sysoff_measure(fd, n_readings, &offset, &ts, &delay)) {
err = -1;
break;
}
offset -= sync_offset * NS_PER_SEC;
- update_clock(clock, offset, ts);
+ update_clock(clock, offset, ts, delay);
}
return err;
}
@@ -267,17 +274,18 @@ static int do_phc_loop(struct clock *clock, clockid_t src,
int rate, int n_readings, int sync_offset)
{
uint64_t ts;
- int64_t offset;
+ int64_t offset, delay;

clock->source_label = "phc";

while (1) {
usleep(1000000 / rate);
- if (!read_phc(src, clock->clkid, n_readings, &offset, &ts)) {
+ if (!read_phc(src, clock->clkid, n_readings,
+ &offset, &ts, &delay)) {
continue;
}
offset -= sync_offset * NS_PER_SEC;
- update_clock(clock, offset, ts);
+ update_clock(clock, offset, ts, delay);
}
return 0;
}
diff --git a/sysoff.c b/sysoff.c
index 37a9664..f7b6240 100644
--- a/sysoff.c
+++ b/sysoff.c
@@ -52,7 +52,8 @@ static void insertion_sort(int length, int64_t interval, int64_t offset, uint64_
samples[i+1].timestamp = ts;
}

-static int64_t sysoff_estimate(struct ptp_clock_time *pct, int n_samples, uint64_t *ts)
+static int64_t sysoff_estimate(struct ptp_clock_time *pct, int n_samples,
+ uint64_t *ts, int64_t *delay)
{
int64_t t1, t2, tp;
int64_t interval, offset;
@@ -67,10 +68,12 @@ static int64_t sysoff_estimate(struct ptp_clock_time *pct, int n_samples, uint64
insertion_sort(i, interval, offset, (t2 + t1) / 2);
}
*ts = samples[0].timestamp;
+ *delay = samples[0].interval;
return samples[0].offset;
}

-int sysoff_measure(int fd, int n_samples, int64_t *result, uint64_t *ts)
+int sysoff_measure(int fd, int n_samples,
+ int64_t *result, uint64_t *ts, int64_t *delay)
{
struct ptp_sys_offset pso;
pso.n_samples = n_samples;
@@ -78,13 +81,13 @@ int sysoff_measure(int fd, int n_samples, int64_t *result, uint64_t *ts)
perror("ioctl PTP_SYS_OFFSET");
return SYSOFF_RUN_TIME_MISSING;
}
- *result = sysoff_estimate(pso.ts, n_samples, ts);
+ *result = sysoff_estimate(pso.ts, n_samples, ts, delay);
return SYSOFF_SUPPORTED;
}

int sysoff_probe(int fd, int n_samples)
{
- int64_t junk;
+ int64_t junk, delay;
uint64_t ts;

if (n_samples > PTP_MAX_SAMPLES) {
@@ -94,12 +97,13 @@ int sysoff_probe(int fd, int n_samples)
return SYSOFF_RUN_TIME_MISSING;
}

- return sysoff_measure(fd, n_samples, &junk, &ts);
+ return sysoff_measure(fd, n_samples, &junk, &ts, &delay);
}

#else /* !PTP_SYS_OFFSET */

-int sysoff_measure(int fd, int n_samples, int64_t *result, uint64_t *ts)
+int sysoff_measure(int fd, int n_samples,
+ int64_t *result, uint64_t *ts, int64_t *delay)
{
return SYSOFF_COMPILE_TIME_MISSING;
}
diff --git a/sysoff.h b/sysoff.h
index f2e481e..cb70265 100644
--- a/sysoff.h
+++ b/sysoff.h
@@ -39,6 +39,8 @@ int sysoff_probe(int fd, int n_samples);
* @param n_samples The number of consecutive readings to make.
* @param result The estimated offset in nanoseconds.
* @param ts The system time corresponding to the 'result'.
+ * @param delay The delay in reading of the clock in nanoseconds.
* @return One of the SYSOFF_ enumeration values.
*/
-int sysoff_measure(int fd, int n_samples, int64_t *result, uint64_t *ts);
+int sysoff_measure(int fd, int n_samples,
+ int64_t *result, uint64_t *ts, int64_t *delay);
--
1.7.11.7
Richard Cochran
2013-02-06 19:17:42 UTC
Permalink
Post by Miroslav Lichvar
If the delay is known, print it together with the offset and frequency.
Remove the time stamp from the output to fit it into 80 chars.
...
Post by Miroslav Lichvar
@@ -146,6 +146,7 @@ static int read_phc(clockid_t clkid, clockid_t sysclk, int readings,
*ts = tdst2.tv_sec * NS_PER_SEC + tdst2.tv_nsec;
}
}
+ *delay = best_interval;
return 1;
}
I don't mind that you print this information, but I think the word
"delay" is a bit misleading here. Isn't the value really the total
time it takes to make three clock readings (A,B,A) ?

Thanks,
Richard
Miroslav Lichvar
2013-02-07 12:20:39 UTC
Permalink
Post by Richard Cochran
Post by Miroslav Lichvar
If the delay is known, print it together with the offset and frequency.
Remove the time stamp from the output to fit it into 80 chars.
...
Post by Miroslav Lichvar
@@ -146,6 +146,7 @@ static int read_phc(clockid_t clkid, clockid_t sysclk, int readings,
*ts = tdst2.tv_sec * NS_PER_SEC + tdst2.tv_nsec;
}
}
+ *delay = best_interval;
return 1;
}
I don't mind that you print this information, but I think the word
"delay" is a bit misleading here. Isn't the value really the total
time it takes to make three clock readings (A,B,A) ?
I'm open to suggestions for a better label. It's the time it takes to
read A and B. As A is usually at least an order of magnitude faster
than B, "delay in reading B" seemed ok to me.

Thanks,
--
Miroslav Lichvar
Miroslav Lichvar
2013-02-05 16:36:16 UTC
Permalink
Add new options to ptp4l and phc2sys to print summary statistics of the
clock instead of the individual samples.

Signed-off-by: Miroslav Lichvar <***@redhat.com>
---
clock.c | 93 +++++++++++++++++++++++++++++++++++++++++++++++++++++++------
clock.h | 3 +-
config.c | 5 ++++
config.h | 1 +
default.cfg | 1 +
gPTP.cfg | 1 +
makefile | 8 +++---
phc2sys.8 | 11 ++++++++
phc2sys.c | 75 ++++++++++++++++++++++++++++++++++++++++++++-----
ptp4l.8 | 10 +++++++
ptp4l.c | 4 ++-
stats.c | 87 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++
stats.h | 77 ++++++++++++++++++++++++++++++++++++++++++++++++++
13 files changed, 354 insertions(+), 22 deletions(-)
create mode 100644 stats.c
create mode 100644 stats.h

diff --git a/clock.c b/clock.c
index 413963c..e7188e3 100644
--- a/clock.c
+++ b/clock.c
@@ -31,6 +31,7 @@
#include "phc.h"
#include "port.h"
#include "servo.h"
+#include "stats.h"
#include "print.h"
#include "tlv.h"
#include "uds.h"
@@ -50,6 +51,13 @@ struct freq_estimator {
int count;
};

+struct clock_stats {
+ struct stats *offset;
+ struct stats *freq;
+ struct stats *delay;
+ int max_count;
+};
+
struct clock {
clockid_t clkid;
struct servo *servo;
@@ -80,6 +88,8 @@ struct clock {
tmv_t t1;
tmv_t t2;
struct clock_description desc;
+ struct clock_stats stats;
+ int stats_interval;
};

struct clock the_clock;
@@ -104,6 +114,9 @@ void clock_destroy(struct clock *c)
}
servo_destroy(c->servo);
mave_destroy(c->avg_delay);
+ stats_destroy(c->stats.offset);
+ stats_destroy(c->stats.freq);
+ stats_destroy(c->stats.delay);
memset(c, 0, sizeof(*c));
msg_cleanup();
}
@@ -214,6 +227,40 @@ static int clock_master_lost(struct clock *c)
return 1;
}

+static void clock_stats_update(struct clock_stats *s,
+ int64_t offset, double freq)
+{
+ struct stats_result offset_stats, freq_stats, delay_stats;
+
+ stats_add_value(s->offset, offset);
+ stats_add_value(s->freq, freq);
+
+ if (stats_get_num_values(s->offset) < s->max_count)
+ return;
+
+ stats_get_result(s->offset, &offset_stats);
+ stats_get_result(s->freq, &freq_stats);
+
+ /* Path delay stats are updated separately, they may be empty. */
+ if (!stats_get_result(s->delay, &delay_stats)) {
+ pr_info("rms %4.0f max %4.0f "
+ "freq %+6.0f +/- %3.0f "
+ "delay %5.0f +/- %3.0f",
+ offset_stats.rms, offset_stats.max_abs,
+ freq_stats.mean, freq_stats.stddev,
+ delay_stats.mean, delay_stats.stddev);
+ } else {
+ pr_info("rms %4.0f max %4.0f "
+ "freq %+6.0f +/- %3.0f",
+ offset_stats.rms, offset_stats.max_abs,
+ freq_stats.mean, freq_stats.stddev);
+ }
+
+ stats_reset(s->offset);
+ stats_reset(s->freq);
+ stats_reset(s->delay);
+}
+
static enum servo_state clock_no_adjust(struct clock *c)
{
double fui;
@@ -260,9 +307,13 @@ static enum servo_state clock_no_adjust(struct clock *c)
tmv_dbl(tmv_sub(c->t2, f->ingress1));
freq = (1.0 - ratio) * 1e9;

- pr_info("master offset %10" PRId64 " s%d freq %+7.0f "
- "path delay %9" PRId64,
- c->master_offset, state, freq, c->path_delay);
+ if (c->stats.max_count > 1) {
+ clock_stats_update(&c->stats, c->master_offset, freq);
+ } else {
+ pr_info("master offset %10" PRId64 " s%d freq %+7.0f "
+ "path delay %9" PRId64,
+ c->master_offset, state, freq, c->path_delay);
+ }

fui = 1.0 + (c->status.cumulativeScaledRateOffset + 0.0) / POW2_41;

@@ -415,7 +466,7 @@ UInteger8 clock_class(struct clock *c)

struct clock *clock_create(int phc_index, struct interface *iface, int count,
enum timestamp_type timestamping, struct default_ds *dds,
- enum servo_type servo)
+ enum servo_type servo, int stats_interval)
{
int i, fadj = 0, max_adj = 0.0, sw_ts = timestamping == TS_SOFTWARE ? 1 : 0;
struct clock *c = &the_clock;
@@ -468,6 +519,15 @@ struct clock *clock_create(int phc_index, struct interface *iface, int count,
pr_err("Failed to create moving average");
return NULL;
}
+ c->stats_interval = stats_interval;
+ c->stats.offset = stats_create();
+ c->stats.freq = stats_create();
+ c->stats.delay = stats_create();
+ if (!c->stats.offset || !c->stats.freq || !c->stats.delay) {
+ pr_err("failed to create stats");
+ return NULL;
+ }
+ c->stats.max_count = 0;

c->dds = dds->dds;

@@ -795,12 +855,18 @@ void clock_path_delay(struct clock *c, struct timespec req, struct timestamp rx,
c->cur.meanPathDelay = tmv_to_TimeInterval(c->path_delay);

pr_debug("path delay %10lld %10lld", c->path_delay, pd);
+
+ if (c->stats.delay)
+ stats_add_value(c->stats.delay, pd);
}

void clock_peer_delay(struct clock *c, tmv_t ppd, double nrr)
{
c->path_delay = ppd;
c->nrr = nrr;
+
+ if (c->stats.delay)
+ stats_add_value(c->stats.delay, ppd);
}

void clock_remove_fda(struct clock *c, struct port *p, struct fdarray fda)
@@ -864,9 +930,13 @@ enum servo_state clock_synchronize(struct clock *c,

adj = servo_sample(c->servo, c->master_offset, ingress, &state);

- pr_info("master offset %10" PRId64 " s%d freq %+7.0f "
- "path delay %9" PRId64,
- c->master_offset, state, adj, c->path_delay);
+ if (c->stats.max_count > 1) {
+ clock_stats_update(&c->stats, c->master_offset, adj);
+ } else {
+ pr_info("master offset %10" PRId64 " s%d freq %+7.0f "
+ "path delay %9" PRId64,
+ c->master_offset, state, adj, c->path_delay);
+ }

switch (state) {
case SERVO_UNLOCKED:
@@ -886,12 +956,17 @@ enum servo_state clock_synchronize(struct clock *c,

void clock_sync_interval(struct clock *c, int n)
{
- int shift = c->freq_est_interval - n;
+ int shift;

+ shift = c->freq_est_interval - n;
if (shift < 0)
shift = 0;
-
c->fest.max_count = (1 << shift);
+
+ shift = c->stats_interval - n;
+ if (shift < 0)
+ shift = 0;
+ c->stats.max_count = (1 << shift);
}

struct timePropertiesDS *clock_time_properties(struct clock *c)
diff --git a/clock.h b/clock.h
index 581fa14..6bc98cd 100644
--- a/clock.h
+++ b/clock.h
@@ -67,11 +67,12 @@ UInteger8 clock_class(struct clock *c);
* @param timestamping The timestamping mode for this clock.
* @param dds A pointer to a default data set for the clock.
* @param servo The servo that this clock will use.
+ * @param stats_interval Interval in which are printed clock statistics.
* @return A pointer to the single global clock instance.
*/
struct clock *clock_create(int phc_index, struct interface *iface, int count,
enum timestamp_type timestamping, struct default_ds *dds,
- enum servo_type servo);
+ enum servo_type servo, int stats_interval);

/**
* Obtains a clock's default data set.
diff --git a/config.c b/config.c
index e4b9c22..d0bbd63 100644
--- a/config.c
+++ b/config.c
@@ -378,6 +378,11 @@ static enum parser_result parse_global_setting(const char *option,
for (i = 0; i < OUI_LEN; i++)
cfg->dds.clock_desc.manufacturerIdentity[i] = oui[i];

+ } else if (!strcmp(option, "summary_interval")) {
+ if (1 != sscanf(value, "%d", &val))
+ return BAD_VALUE;
+ cfg->summary_interval = val;
+
} else
return NOT_PARSED;

diff --git a/config.h b/config.h
index 497d683..3af193c 100644
--- a/config.h
+++ b/config.h
@@ -76,6 +76,7 @@ struct config {
int print_level;
int use_syslog;
int verbose;
+ int summary_interval;
};

int config_read(char *name, struct config *cfg);
diff --git a/default.cfg b/default.cfg
index 10401ac..7b3e2f7 100644
--- a/default.cfg
+++ b/default.cfg
@@ -32,6 +32,7 @@ follow_up_info 0
tx_timestamp_retries 100
use_syslog 1
verbose 0
+summary_interval 0
#
# Servo Options
#
diff --git a/gPTP.cfg b/gPTP.cfg
index 3c47e28..ecd5f71 100644
--- a/gPTP.cfg
+++ b/gPTP.cfg
@@ -31,6 +31,7 @@ follow_up_info 1
tx_timestamp_retries 100
use_syslog 1
verbose 0
+summary_interval 0
#
# Servo options
#
diff --git a/makefile b/makefile
index 9f2b587..671de48 100644
--- a/makefile
+++ b/makefile
@@ -30,8 +30,8 @@ CFLAGS = -Wall $(VER) $(INC) $(DEBUG) $(FEAT_CFLAGS) $(EXTRA_CFLAGS)
LDLIBS = -lm -lrt $(EXTRA_LDFLAGS)
PRG = ptp4l pmc phc2sys hwstamp_ctl
OBJ = bmc.o clock.o config.o fsm.o ptp4l.o mave.o msg.o phc.o pi.o port.o \
- print.o raw.o servo.o sk.o tlv.o tmtab.o transport.o udp.o udp6.o uds.o util.o \
- version.o
+ print.o raw.o servo.o sk.o stats.o tlv.o tmtab.o transport.o udp.o udp6.o \
+ uds.o util.o version.o

OBJECTS = $(OBJ) hwstamp_ctl.o phc2sys.o pmc.o pmc_common.o sysoff.o
SRC = $(OBJECTS:.o=.c)
@@ -52,8 +52,8 @@ ptp4l: $(OBJ)
pmc: msg.o pmc.o pmc_common.o print.o raw.o sk.o tlv.o transport.o udp.o \
udp6.o uds.o util.o version.o

-phc2sys: msg.o phc2sys.o pmc_common.o print.o pi.o servo.o raw.o sk.o sysoff.o \
- tlv.o transport.o udp.o udp6.o uds.o util.o version.o
+phc2sys: msg.o phc2sys.o pmc_common.o print.o pi.o servo.o raw.o sk.o stats.o \
+ sysoff.o tlv.o transport.o udp.o udp6.o uds.o util.o version.o

hwstamp_ctl: hwstamp_ctl.o version.o

diff --git a/phc2sys.8 b/phc2sys.8
index 578d4ab..0542ba7 100644
--- a/phc2sys.8
+++ b/phc2sys.8
@@ -27,6 +27,8 @@ phc2sys \- synchronize two clocks
] [
.BI \-O " offset"
] [
+.BI \-u " summary-updates"
+] [
.B \-w
] [
.BI \-l " print-level"
@@ -112,6 +114,15 @@ Without
.B \-w
the default is 0.
.TP
+.BI \-u " summary-updates"
+Specify the number of clock updates included in summary statistics. The
+statistics include offset root mean square (RMS), maximum absolute offset,
+frequency offset mean and standard deviation, and mean of the delay in clock
+readings and standard deviation. The units are nanoseconds and parts per
+billion (ppb). If zero, the individual samples are printed instead of the
+statistics. The messages are printed at the LOG_INFO level.
+The default is 0 (disabled).
+.TP
.B \-w
Wait until ptp4l is in a synchronized state.
.TP
diff --git a/phc2sys.c b/phc2sys.c
index c33daea..7d6bb97 100644
--- a/phc2sys.c
+++ b/phc2sys.c
@@ -42,6 +42,7 @@
#include "print.h"
#include "servo.h"
#include "sk.h"
+#include "stats.h"
#include "sysoff.h"
#include "tlv.h"
#include "version.h"
@@ -155,8 +156,47 @@ struct clock {
clockid_t clkid;
struct servo *servo;
const char *source_label;
+ struct stats *offset_stats;
+ struct stats *freq_stats;
+ struct stats *delay_stats;
+ int stats_max_count;
};

+static void update_clock_stats(struct clock *clock,
+ int64_t offset, double freq, int64_t delay)
+{
+ struct stats_result offset_stats, freq_stats, delay_stats;
+
+ stats_add_value(clock->offset_stats, offset);
+ stats_add_value(clock->freq_stats, freq);
+ if (delay >= 0)
+ stats_add_value(clock->delay_stats, delay);
+
+ if (stats_get_num_values(clock->offset_stats) < clock->stats_max_count)
+ return;
+
+ stats_get_result(clock->offset_stats, &offset_stats);
+ stats_get_result(clock->freq_stats, &freq_stats);
+
+ if (!stats_get_result(clock->delay_stats, &delay_stats)) {
+ pr_info("rms %4.0f max %4.0f "
+ "freq %+6.0f +/- %3.0f "
+ "delay %5.0f +/- %3.0f",
+ offset_stats.rms, offset_stats.max_abs,
+ freq_stats.mean, freq_stats.stddev,
+ delay_stats.mean, delay_stats.stddev);
+ } else {
+ pr_info("rms %4.0f max %4.0f "
+ "freq %+6.0f +/- %3.0f",
+ offset_stats.rms, offset_stats.max_abs,
+ freq_stats.mean, freq_stats.stddev);
+ }
+
+ stats_reset(clock->offset_stats);
+ stats_reset(clock->freq_stats);
+ stats_reset(clock->delay_stats);
+}
+
static void update_clock(struct clock *clock,
int64_t offset, uint64_t ts, int64_t delay)
{
@@ -176,13 +216,17 @@ static void update_clock(struct clock *clock,
break;
}

- if (delay >= 0) {
- pr_info("%s offset %9" PRId64 " s%d freq %+7.0f "
- "delay %6" PRId64,
- clock->source_label, offset, state, ppb, delay);
+ if (clock->offset_stats) {
+ update_clock_stats(clock, offset, ppb, delay);
} else {
- pr_info("%s offset %9" PRId64 " s%d freq %+7.0f",
- clock->source_label, offset, state, ppb);
+ if (delay >= 0) {
+ pr_info("%s offset %9" PRId64 " s%d freq %+7.0f "
+ "delay %6" PRId64,
+ clock->source_label, offset, state, ppb, delay);
+ } else {
+ pr_info("%s offset %9" PRId64 " s%d freq %+7.0f",
+ clock->source_label, offset, state, ppb);
+ }
}
}

@@ -424,6 +468,7 @@ static void usage(char *progname)
" -R [rate] slave clock update rate in HZ (1)\n"
" -N [num] number of master clock readings per update (5)\n"
" -O [offset] slave-master time offset (0)\n"
+ " -u [num] number of clock updates in summary stats (0)\n"
" -w wait for ptp4l\n"
" -h prints this message and exits\n"
" -v prints the software version and exits\n"
@@ -447,7 +492,8 @@ int main(int argc, char *argv[])
/* Process the command line arguments. */
progname = strrchr(argv[0], '/');
progname = progname ? 1+progname : argv[0];
- while (EOF != (c = getopt(argc, argv, "c:d:hs:P:I:S:R:N:O:i:wl:mqv"))) {
+ while (EOF != (c = getopt(argc, argv,
+ "c:d:hs:P:I:S:R:N:O:i:u:wl:mqv"))) {
switch (c) {
case 'c':
dst_clock.clkid = clock_open(optarg);
@@ -485,6 +531,9 @@ int main(int argc, char *argv[])
case 'i':
ethdev = optarg;
break;
+ case 'u':
+ dst_clock.stats_max_count = atoi(optarg);
+ break;
case 'w':
wait_sync = 1;
break;
@@ -530,6 +579,18 @@ int main(int argc, char *argv[])
return -1;
}

+ if (dst_clock.stats_max_count > 0) {
+ dst_clock.offset_stats = stats_create();
+ dst_clock.freq_stats = stats_create();
+ dst_clock.delay_stats = stats_create();
+ if (!dst_clock.offset_stats ||
+ !dst_clock.freq_stats ||
+ !dst_clock.delay_stats) {
+ fprintf(stderr, "failed to create stats");
+ return -1;
+ }
+ }
+
print_set_progname(progname);
print_set_verbose(verbose);
print_set_syslog(use_syslog);
diff --git a/ptp4l.8 b/ptp4l.8
index 370b7cf..3ee222d 100644
--- a/ptp4l.8
+++ b/ptp4l.8
@@ -307,6 +307,16 @@ The default is 0 (disabled).
Print messages to the system log if enabled.
The default is 1 (enabled).
.TP
+.B summary_interval
+The time interval in which are printed summary statistics of the clock. It is
+specified as a power of two in seconds. The statistics include offset root mean
+square (RMS), maximum absolute offset, frequency offset mean and standard
+deviation, and path delay mean and standard deviation. The units are
+nanoseconds and parts per billion (ppb). If there is only one clock update in
+the interval, the sample will be printed instead of the statistics. The
+messages are printed at the LOG_INFO level.
+The default is 0 (1 second).
+.TP
.B time_stamping
The time stamping method. The allowed values are hardware, software and legacy.
The default is hardware.
diff --git a/ptp4l.c b/ptp4l.c
index 3da3388..2a8eeb0 100644
--- a/ptp4l.c
+++ b/ptp4l.c
@@ -99,6 +99,7 @@ static struct config cfg_settings = {
.print_level = LOG_INFO,
.use_syslog = 1,
.verbose = 0,
+ .summary_interval = 0,

.cfg_ignore = 0,
};
@@ -351,7 +352,8 @@ int main(int argc, char *argv[])

clock = clock_create(phc_index, iface, cfg_settings.nports,
*timestamping, &cfg_settings.dds,
- cfg_settings.clock_servo);
+ cfg_settings.clock_servo,
+ cfg_settings.summary_interval);
if (!clock) {
fprintf(stderr, "failed to create a clock\n");
return -1;
diff --git a/stats.c b/stats.c
new file mode 100644
index 0000000..cc8f72d
--- /dev/null
+++ b/stats.c
@@ -0,0 +1,87 @@
+/**
+ * @file stats.c
+ * @note Copyright (C) 2013 Miroslav Lichvar <***@redhat.com>
+ *
+ * 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.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+#include <math.h>
+#include <string.h>
+#include <stdlib.h>
+
+#include "stats.h"
+
+struct stats {
+ int num;
+ double min;
+ double max;
+ double mean;
+ double sum_sqr;
+ double sum_diff_sqr;
+};
+
+struct stats *stats_create()
+{
+ struct stats *stats;
+
+ stats = calloc(1, sizeof *stats);
+ return stats;
+}
+
+void stats_destroy(struct stats *stats)
+{
+ free(stats);
+}
+
+void stats_add_value(struct stats *stats,
+ double value)
+{
+ double old_mean = stats->mean;
+
+ if (!stats->num || stats->max < value)
+ stats->max = value;
+ if (!stats->num || stats->min > value)
+ stats->min = value;
+
+ stats->num++;
+ stats->mean = old_mean + (value - old_mean) / stats->num;
+ stats->sum_sqr += value * value;
+ stats->sum_diff_sqr += (value - old_mean) * (value - stats->mean);
+}
+
+int stats_get_num_values(struct stats *stats)
+{
+ return stats->num;
+}
+
+int stats_get_result(struct stats *stats,
+ struct stats_result *result)
+{
+ if (!stats->num)
+ return -1;
+
+ result->min = stats->min;
+ result->max = stats->max;
+ result->max_abs = stats->max > -stats->min ? stats->max : -stats->min;
+ result->mean = stats->mean;
+ result->rms = sqrt(stats->sum_sqr / stats->num);
+ result->stddev = sqrt(stats->sum_diff_sqr / stats->num);
+
+ return 0;
+}
+
+void stats_reset(struct stats *stats)
+{
+ memset(stats, 0, sizeof *stats);
+}
diff --git a/stats.h b/stats.h
new file mode 100644
index 0000000..2e70f8f
--- /dev/null
+++ b/stats.h
@@ -0,0 +1,77 @@
+/**
+ * @file stats.h
+ * @brief Implements various statistics.
+ * @note Copyright (C) 2013 Miroslav Lichvar <***@redhat.com>
+ *
+ * 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.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+#ifndef HAVE_STATS_H
+#define HAVE_STATS_H
+
+/** Opaque type */
+struct stats;
+
+/**
+ * Create a new instance of statistics.
+ * @return A pointer to a new stats on success, NULL otherwise.
+ */
+struct stats *stats_create();
+
+/**
+ * Destroy an instance of stats.
+ * @param servo Pointer to stats obtained via @ref stats_create().
+ */
+void stats_destroy(struct stats *stats);
+
+/**
+ * Add a new value to the stats.
+ * @param stats Pointer to stats obtained via @ref stats_create().
+ * @param value The measured value.
+ */
+void stats_add_value(struct stats *stats,
+ double value);
+
+/**
+ * Get the number of values collected in the stats so far.
+ * @param stats Pointer to stats obtained via @ref stats_create().
+ * @return The number of values.
+ */
+int stats_get_num_values(struct stats *stats);
+
+struct stats_result {
+ double min;
+ double max;
+ double max_abs;
+ double mean;
+ double rms;
+ double stddev;
+};
+
+/**
+ * Obtain the results of the calculated statistics.
+ * @param stats Pointer to stats obtained via @ref stats_create().
+ * @param stats_result Pointer to stats_result to store the results.
+ * @return Zero on success, non-zero if no values were added.
+ */
+int stats_get_result(struct stats *stats,
+ struct stats_result *result);
+
+/**
+ * Reset all statistics.
+ * @param stats Pointer to stats obtained via @ref stats_create().
+ */
+void stats_reset(struct stats *stats);
+
+#endif
--
1.7.11.7
Richard Cochran
2013-02-05 17:45:30 UTC
Permalink
This post might be inappropriate. Click to display it.
Richard Cochran
2013-02-06 19:52:09 UTC
Permalink
Post by Miroslav Lichvar
@@ -468,6 +519,15 @@ struct clock *clock_create(int phc_index, struct interface *iface, int count,
pr_err("Failed to create moving average");
return NULL;
}
+ c->stats_interval = stats_interval;
+ c->stats.offset = stats_create();
+ c->stats.freq = stats_create();
+ c->stats.delay = stats_create();
+ if (!c->stats.offset || !c->stats.freq || !c->stats.delay) {
+ pr_err("failed to create stats");
+ return NULL;
+ }
+ c->stats.max_count = 0;
This could be the trouble that you wanted to fix using
clock_sync_interval(). The default here should be set using
freq_est_interval and the default logSyncInterval.

The exisiting c->fest.max_count is hard coded initially to 2, which is
correct for the default freq_est_interval, but I guess it should be
fixed. The port's similar p->nrate.max_count looks okay to me.

Thanks,
Richard
Miroslav Lichvar
2013-02-07 12:14:49 UTC
Permalink
Post by Richard Cochran
Post by Miroslav Lichvar
@@ -468,6 +519,15 @@ struct clock *clock_create(int phc_index, struct interface *iface, int count,
pr_err("Failed to create moving average");
return NULL;
}
+ c->stats_interval = stats_interval;
+ c->stats.offset = stats_create();
+ c->stats.freq = stats_create();
+ c->stats.delay = stats_create();
+ if (!c->stats.offset || !c->stats.freq || !c->stats.delay) {
+ pr_err("failed to create stats");
+ return NULL;
+ }
+ c->stats.max_count = 0;
This could be the trouble that you wanted to fix using
clock_sync_interval().
Yes, that's the problem I was trying to fix with that patch. I try to
avoid code duplication and the freq max_count wasn't set correctly
either, so it seemed to me calling clock_sync_interval() in the create
function would be a good solution. Then I thought what happens when
there are two ports with different logSyncInterval and the clock sync
switches between them. I'm not sure if/how such transision is actually
handled and if clock_sync_interval wouldn't be called from port.c.
Also, I didn't want to have the assumption in clock.c that
logSyncInterval is 0 by default.
Post by Richard Cochran
The default here should be set using
freq_est_interval and the default logSyncInterval.
You mean stats_interval and 0?
Post by Richard Cochran
The exisiting c->fest.max_count is hard coded initially to 2, which is
correct for the default freq_est_interval, but I guess it should be
fixed. The port's similar p->nrate.max_count looks okay to me.
Would be ok to set both max_count variables to 0 and call
clock_sync_interval(c, 0) in clock_create?

Thanks,
--
Miroslav Lichvar
Richard Cochran
2013-02-07 14:46:43 UTC
Permalink
Post by Miroslav Lichvar
Would be ok to set both max_count variables to 0 and call
clock_sync_interval(c, 0) in clock_create?
Yes, please.

Thanks,
Richard

Richard Cochran
2013-02-06 18:56:35 UTC
Permalink
Applied these nine...
phc2sys: Add option to set step threshold.
Move Unix domain sockets to /var/run.
pmc: Allow commands on command line.
phc2sys: Open PPS device sooner.
phc2sys: Use printing facility.
Print messages with level below LOG_NOTICE to stderr.
Check sample time stamps in drift calculation.
Update comment in pi.c.
Remove trailing whitespaces.
About these last four, I don't know yet. The last one doesn't even
compile...
Update clock sync interval.
Change label of frequency offset.
phc2sys: Print clock reading delay.
Add summary statistics.
Thanks,
Richard
Miroslav Lichvar
2013-02-07 12:23:32 UTC
Permalink
Post by Richard Cochran
About these last four, I don't know yet. The last one doesn't even
compile...
Update clock sync interval.
Change label of frequency offset.
phc2sys: Print clock reading delay.
Add summary statistics.
The compilation problem was actually in the last but one patch. The
"[PATCHv2 12/13] phc2sys: Print clock reading delay." should be ok,
please let me know if it's not or if you prefer me to resend the four
patches in a new set.

Thanks,
--
Miroslav Lichvar
Richard Cochran
2013-02-07 14:44:21 UTC
Permalink
Post by Miroslav Lichvar
Post by Richard Cochran
About these last four, I don't know yet. The last one doesn't even
compile...
Update clock sync interval.
Change label of frequency offset.
phc2sys: Print clock reading delay.
Add summary statistics.
The compilation problem was actually in the last but one patch. The
"[PATCHv2 12/13] phc2sys: Print clock reading delay." should be ok,
please let me know if it's not or if you prefer me to resend the four
patches in a new set.
Please resend a new series.

Thanks,
Richard
Loading...