X-Git-Url: http://rtime.felk.cvut.cz/gitweb/canping.git/blobdiff_plain/6991851c166330d9dd36cc88cbb1ef839f5c0c7c..HEAD:/src/vca_canping.c diff --git a/src/vca_canping.c b/src/vca_canping.c index c3fbb07..87c3fd3 100644 --- a/src/vca_canping.c +++ b/src/vca_canping.c @@ -2,8 +2,8 @@ /* File: vca_canping.c - utility to test CAN functionality and throughput */ /* */ /* LibVCA - Versatile CAN/CANopen API library */ -/* Copyright (C) 2005-2006 Michal Sojka, DCE FEE CTU Prague */ -/* Copyright (C) 2006-2009 Pavel Pisa */ +/* Copyright (C) 2005-2009 Michal Sojka, DCE FEE CTU Prague */ +/* Copyright (C) 2006-2023 Pavel Pisa */ /* */ /* LibVCA is free software; you can redistribute it and/or modify it */ /* under terms of the GNU General Public License as published by the */ @@ -28,11 +28,24 @@ #include #include #include +#include #include #include #include #include +#ifndef OMK_FOR_TARGET #include +#define error_with_status error +#else /*OMK_FOR_TARGET*/ +#include +static inline void error_with_status (int __status, int __errnum, const char *__format, ...) +{ + va_list ap; + va_start (ap, __format); + vfprintf (stderr, __format, ap); + va_end (ap); +} +#endif /* TODO: Handle the case where there are more canping slaves running * on one CAN bus. */ @@ -59,7 +72,12 @@ int sched_rtprio; #define dbg(level, fmt, arg...) do { if (level <= DEBUG) { printf("candping: " fmt, ## arg); } } while (0) #endif +#if !defined(OMK_FOR_TARGET) || defined(ERESTART) #define NOT_INTERRUPTED_SYSCALL (errno != EINTR && errno != ERESTART) +#else /*OMK_FOR_TARGET*/ +#define NOT_INTERRUPTED_SYSCALL (errno != EINTR) +#endif /*OMK_FOR_TARGET*/ + #define IS_FINISH_FLAG() (finish_flag) /* Exit codes */ @@ -88,7 +106,7 @@ sem_t ready_sem; /* Thread is ready for execution */ /* Command line options */ -char *option_device = "/dev/can0"; +char *option_device = VCA_DEV_NAME; int option_masters = 0; long int option_first_id = 1000; int option_slaves = 0; @@ -103,7 +121,8 @@ int option_open_once = 0; int option_synch_start = 0; bool option_background = false; char *option_histogram = NULL; - +int option_msg_to_ignore = 0; +char *option_save_all_times = NULL; /* Lists */ typedef struct threads { ul_list_head_t head; @@ -127,6 +146,7 @@ typedef struct thread_data { int timeout; /* number of timeouts */ struct histogram hist; + unsigned *times; /* Array of all measured times */ ul_list_node_t node; } thread_data_t; @@ -168,8 +188,12 @@ void histogram_fprint(struct histogram *h, FILE *f) sum += h->data[i]; cum = sum; for (i = 0; i < h->allocated; i++) { - if (h->data[i] != 0) - fprintf(f, "%d %lld\n", i*h->resolution, cum); + if (h->data[i] != 0) { + if (!getenv("CANPING_MS")) + fprintf(f, "%d %lld\n", i*h->resolution, cum); + else + fprintf(f, "%g %lld\n", 1e-3*(i*h->resolution), cum); + } cum -= h->data[i]; } } @@ -242,8 +266,9 @@ void *master_thread(void *arg) struct canfilt_t canfilt; /* filter for received messages */ if (!option_open_once) { - /* Open can driver */ - if(vca_open_handle(&vcah, option_device, NULL, 0) < 0) { + /* Open the CAN driver and disable (D) reception of + * all messages until we setup a filter below. */ + if(vca_open_handle(&vcah, option_device, "D", 0) < 0) { perror("open"); fprintf(stderr, "Error opening %s (for id %d)\n", option_device, ping_id); exit(EXIT_CANNOT_OPEN); @@ -269,6 +294,12 @@ void *master_thread(void *arg) if (option_histogram) histogram_init(&td->hist, 1000*1000/*max [us]*/, 5/*resolution [us]*/); + + if (option_save_all_times) { + td->times = malloc(sizeof(*td->times)*option_count); + if (!td->times) + error_with_status(1, errno, "malloc times"); + } /* Prepare data structures for the select syscall. */ FD_ZERO (&rdset); @@ -283,7 +314,7 @@ void *master_thread(void *arg) pthread_mutex_unlock(&mut_start); } - while (!IS_FINISH_FLAG() && (option_count == 0 || ping_count++ < option_count)) { + while (!IS_FINISH_FLAG() && (option_count == 0 || ping_count++ < option_count + option_msg_to_ignore)) { /* Send a ping message */ pingmsg.flags=0; pingmsg.id=ping_id; @@ -336,21 +367,25 @@ void *master_thread(void *arg) printf("%d:%ld\n", ping_id, time); break; case 3: - printf("Pong response for id %d received in %ld us\n", ping_id, time); + printf("Pong response %d for id %d received in %ld us\n", ping_count, ping_id, time); break; } /* Update statistics */ - td->count++; - td->mean = - td->mean * ((double)(td->count - 1) / td->count) + - (double)time / td->count; - td->moment2nd = - td->moment2nd * ((double)(td->count - 1) / td->count) + - (double)time*time / td->count; - if (time > td->max) td->max = time; - if (time < td->min) td->min = time; - if (option_histogram) - histogram_add(&td->hist, time); + if (ping_count > option_msg_to_ignore) { + td->count++; + td->mean = + td->mean * ((double)(td->count - 1) / td->count) + + (double)time / td->count; + td->moment2nd = + td->moment2nd * ((double)(td->count - 1) / td->count) + + (double)time*time / td->count; + if (time > td->max) td->max = time; + if (time < td->min) td->min = time; + if (option_histogram) + histogram_add(&td->hist, time); + if (option_save_all_times) + td->times[ping_count - 1 - option_msg_to_ignore] = time; + } total_count++; } /* read */ } @@ -384,6 +419,21 @@ void *master_thread(void *arg) fclose(f); } + if (option_save_all_times) { + FILE *f; + char buf[100]; + int i; + snprintf(buf, sizeof(buf), "%s-%d.dat", option_save_all_times, ping_id); + f = fopen(buf, "w"); + for (i=0; itimes[i]); + else + fprintf(f, "%g\n", 1e-3*td->times[i]); + } + fclose(f); + } + sem_post(&finish_sem); return (void *)ret; } @@ -435,8 +485,9 @@ void *slave_thread(void *arg) struct canfilt_t canfilt; /* filter for received messages */ if (!option_open_once) { - /* Open the CAN driver */ - if(vca_open_handle(&vcah, option_device, NULL, 0) < 0) { + /* Open the CAN driver and disable (D) reception of + * all messages until we setup a filter below. */ + if(vca_open_handle(&vcah, option_device, "D", 0) < 0) { perror("open"); printf("Error opening %s (for id %d)\n", option_device, ping_id); exit(EXIT_CANNOT_OPEN); @@ -575,10 +626,12 @@ void print_help(void) " -b go to background (fork) after initialization, prints child PID\n" " -c count how many messages each master sends\n" " -d dev device (e.g. /dev/can1)\n" + " -e prefix save all measured times in file -.dat\n" " -g prefix store cumulative histogram in file -.dat\n" " -h print this help\n" " -i id id of first master message\n" " -l length length of the messages (0..8)\n" + " -n number ignore first messages\n" " -o open a device only once for all threads (doesn't work)\n" /* due to filters */ " -t timeout timeout in seconds (default 4 s)\n" " -v be verbose (use more than once to increase verbosity)\n" @@ -598,8 +651,10 @@ int parse_options(int argc, char *argv[]) { int c; +#ifndef OMK_FOR_TARGET opterr = 0; - while ((c = getopt (argc, argv, "bc:d:g:hi:l:m:os:t:vw:yrR:")) != -1) +#endif /*OMK_FOR_TARGET*/ + while ((c = getopt (argc, argv, "bc:d:e:g:hi:l:m:n:os:t:vw:yrR:")) != -1) switch (c) { case 'b': @@ -611,6 +666,9 @@ int parse_options(int argc, char *argv[]) case 'd': option_device = optarg; break; + case 'e': + option_save_all_times = optarg; + break; case 'g': option_histogram = optarg; break; @@ -629,6 +687,9 @@ int parse_options(int argc, char *argv[]) case 'm': option_masters = atoi(optarg); break; + case 'n': + option_msg_to_ignore = atoi(optarg); + break; case 'o': option_open_once = 1; break; @@ -766,7 +827,9 @@ int main(int argc, char *argv[]) if(sched_policy != SCHED_OTHER) { if(set_sched_policy_and_prio(sched_policy, sched_rtprio) <0) exit(EXIT_BAD_PARAM); +#if !defined(OMK_FOR_TARGET) || (defined(MCL_CURRENT) && defined(MCL_FUTURE)) mlockall(MCL_CURRENT | MCL_FUTURE); +#endif /*OMK_FOR_TARGET*/ } #endif @@ -796,17 +859,19 @@ int main(int argc, char *argv[]) sem_t *child_ready; int fork_ret = 0; if ((child_ready = sem_open("canping", O_CREAT)) == NULL) - error(1, errno, "sem_open"); + error_with_status(1, errno, "sem_open"); +#ifndef OMK_FOR_TARGET if (option_background) { /* Go to background when everything is ready */ fork_ret = fork(); if (fork_ret < 0) - error(1, errno, "Cannot go to background"); + error_with_status(1, errno, "Cannot go to background"); if (fork_ret == 0) { int devnull = open("/dev/null", O_WRONLY); dup2(devnull, 1); } } +#endif /*OMK_FOR_TARGET*/ if (fork_ret == 0) { /* Child */