diff options
Diffstat (limited to 'src')
-rwxr-xr-x | src/tests/CMakeLists.txt | 18 | ||||
-rw-r--r-- | src/tests/dlt-test-multi-process-client.c | 232 | ||||
-rwxr-xr-x | src/tests/dlt-test-multi-process.c | 384 | ||||
-rw-r--r-- | src/tests/dlt-test-multi-process.h | 45 |
4 files changed, 678 insertions, 1 deletions
diff --git a/src/tests/CMakeLists.txt b/src/tests/CMakeLists.txt index 1dbd7e8..477c4d9 100755 --- a/src/tests/CMakeLists.txt +++ b/src/tests/CMakeLists.txt @@ -35,6 +35,22 @@ # @licence end@ ######## +set(dlt_test_multi_process_SRCS dlt-test-multi-process) +add_executable(dlt-test-multi-process ${dlt_test_multi_process_SRCS}) +IF(GPROF_DLT_TESTS) + SET(CMAKE_C_FLAGS "-pg") +ENDIF(GPROF_DLT_TESTS) +target_link_libraries(dlt-test-multi-process dlt) +set_target_properties(dlt-test-multi-process PROPERTIES LINKER_LANGUAGE C) + +set(dlt_test_multi_process_client_SRCS dlt-test-multi-process-client) +add_executable(dlt-test-multi-process-client ${dlt_test_multi_process_client_SRCS}) +IF(GPROF_DLT_TESTS) + SET(CMAKE_C_FLAGS "-pg") +ENDIF(GPROF_DLT_TESTS) +target_link_libraries(dlt-test-multi-process-client dlt) +set_target_properties(dlt-test-multi-process-client PROPERTIES LINKER_LANGUAGE C) + set(dlt_test_user_SRCS dlt-test-user) add_executable(dlt-test-user ${dlt_test_user_SRCS}) IF(GPROF_DLT_TESTS) @@ -91,7 +107,7 @@ ENDIF(GPROF_DLT_TESTS) target_link_libraries(dlt-test-filetransfer dlt) set_target_properties(dlt-test-filetransfer PROPERTIES LINKER_LANGUAGE C) -install(TARGETS dlt-test-user dlt-test-client dlt-test-stress-user dlt-test-stress-client dlt-test-stress dlt-test-internal dlt-test-filetransfer +install(TARGETS dlt-test-multi-process dlt-test-multi-process-client dlt-test-user dlt-test-client dlt-test-stress-user dlt-test-stress-client dlt-test-stress dlt-test-internal dlt-test-filetransfer RUNTIME DESTINATION bin COMPONENT base) diff --git a/src/tests/dlt-test-multi-process-client.c b/src/tests/dlt-test-multi-process-client.c new file mode 100644 index 0000000..4bb0c08 --- /dev/null +++ b/src/tests/dlt-test-multi-process-client.c @@ -0,0 +1,232 @@ +/* + * DLT multi process tester + * @licence app begin@ + * + * Copyright (C) 2011, BMW AG - Lassi Marttala <Lassi.LM.Marttala@partner.bmw.de> + * + * This program is free software; you can redistribute it and/or modify it under the terms of the + * GNU Lesser General Public License, version 2.1, as published by the Free Software Foundation. + * 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 Lesser General + * Public License, version 2.1, for more details. + * + * You should have received a copy of the GNU Lesser General Public License, version 2.1, along + * with this program; if not, see <http://www.gnu.org/licenses/lgpl-2.1.html>. + * + * Note that the copyright holders assume that the GNU Lesser General Public License, version 2.1, may + * also be applicable to programs even in cases in which the program is not a library in the technical sense. + * + * Linking DLT statically or dynamically with other modules is making a combined work based on DLT. You may + * license such other modules under the GNU Lesser General Public License, version 2.1. If you do not want to + * license your linked modules under the GNU Lesser General Public License, version 2.1, you + * may use the program under the following exception. + * + * As a special exception, the copyright holders of DLT give you permission to combine DLT + * with software programs or libraries that are released under any license unless such a combination is not + * permitted by the license of such a software program or library. You may copy and distribute such a + * system following the terms of the GNU Lesser General Public License, version 2.1, including this + * special exception, for DLT and the licenses of the other code concerned. + * + * Note that people who make modified versions of DLT are not obligated to grant this special exception + * for their modified versions; it is their choice whether to do so. The GNU Lesser General Public License, + * version 2.1, gives permission to release a modified version without this exception; this exception + * also makes it possible to release a modified version which carries forward this exception. + * + * @licence end@ + */ + +/******************************************************************************* + ** ** + ** SRC-MODULE: dlt-test-multi-process-client.c ** + ** ** + ** TARGET : linux ** + ** ** + ** PROJECT : DLT ** + ** ** + ** AUTHOR : Lassi Marttala <Lassi.LM.Marttala@partner.bmw.de> ** + ** ** + ** PURPOSE : Receive, validate and measure data from multi process tester ** + ** ** + ** REMARKS : ** + ** ** + ** PLATFORM DEPENDANT [yes/no]: yes ** + ** ** + ** TO BE CHANGED BY USER [yes/no]: no ** + ** ** + *******************************************************************************/ +// System includes +#include <string.h> +#include <stdio.h> +#include <unistd.h> +#include <ctype.h> +#include <stdlib.h> +#include <time.h> + +// DLT Library includes +#include "dlt_client.h" +#include "dlt_protocol.h" +#include "dlt_user.h" +// PRivate includes +#include "dlt-test-multi-process.h" + +// Local data structures +typedef struct { + int verbose; +} s_parameters; + +typedef struct { + int messages_received; + int broken_messages_received; + int bytes_received; + int first_message_time; +} s_statistics; + +// Forward declarations +int receive(DltMessage *msg, void *data); + +/** + * Print usage information + */ +void usage(char *name) { + printf("Usage: %s [options] <remote address>\n", name); +} + +/** + * Initialize reasonable default parameters. + */ +void init_params(s_parameters *params) { + params->verbose = 0; +} + +/** + * Read the command line parameters + */ +int read_params(s_parameters *params, int argc, char *argv[]) { + init_params(params); + int c; + opterr = 0; + while ((c = getopt(argc, argv, "v")) != -1) { + switch (c) { + case 'v': + params->verbose = 1; + break; + case '?': + /*if(optopt == '') + { + fprintf(stderr, "Option -%c requires an argument.\n", optopt); + }*/ + if (isprint(optopt)) { + fprintf(stderr, "Unknown option '-%c'.\n", optopt); + } else { + fprintf(stderr, "Unknown option character '\\x%x'.\n", optopt); + } + return -1; + break; + default: + return -1; + } + } + return 0; +} + +/** + * Set the connection parameters for dlt client + */ +int init_dlt_connect(DltClient *client, int argc, char *argv[]) { + char id[4]; + if (argc < 2) + return -1; + client->servIP = argv[argc - 1]; + dlt_set_id(id, ECUID); + return 0; +} + +/** + * Entry point + */ +int main(int argc, char *argv[]) { + s_parameters params; + DltClient client; + + int err = read_params(¶ms, argc, argv); + + if (err != 0) { + usage(argv[0]); + return err; + } + + dlt_client_init(&client, params.verbose); + dlt_client_register_message_callback(receive); + + err = init_dlt_connect(&client, argc, argv); + if (err != 0) { + usage(argv[0]); + return err; + } + + err = dlt_client_connect(&client, params.verbose); + if (err != 0) { + printf("Failed to connect %s\n", client.servIP); + return err; + } + dlt_client_main_loop(&client, NULL, params.verbose); + return 0; +} + +/** + * Print current test statistics + */ +void print_stats(s_statistics stats) +{ + static int last_print_time; + if(last_print_time >= time(NULL)) return; // Only print once a second + printf("\033[2J\033[1;1H"); // Clear screen. + printf("Statistics:\n"); + printf(" Messages received : %d\n", stats.messages_received); + printf(" Broken messages received : %d\n", stats.broken_messages_received); + printf(" Bytes received : %d\n", stats.bytes_received); + printf(" Time running (seconds) : %ld\n", time(NULL)-stats.first_message_time); + printf(" Throughput (msgs/sec)/(B/sec) : %ld/%ld\n", + stats.messages_received/((time(NULL)-stats.first_message_time)+1), + (stats.bytes_received)/((time(NULL)-stats.first_message_time)+1)); + fflush(stdout); + last_print_time = time(NULL); +} +/** + * Callback for dlt client + */ +int receive(DltMessage *msg, void *data) { + static s_statistics stats; + char apid[5]; + memset(apid, 0, 5); + memcpy(apid, msg->extendedheader->apid, 4); + + if(strcmp(apid, DMPT_NAME) != 0) // Skip other messages + return 0; + + if(stats.first_message_time == 0) + { + stats.first_message_time = time(NULL); + } + + int buflen = msg->datasize + 1; + char *buf = malloc(buflen); + memset(buf, 0, buflen); + + dlt_message_payload(msg,buf,buflen-1,DLT_OUTPUT_ASCII,0); + + if(strcmp(buf, PAYLOAD_DATA) == 0) + { + stats.messages_received++; + } + else + { + stats.broken_messages_received++; + } + stats.bytes_received += buflen; + + free(buf); + + print_stats(stats); + return 0; +} diff --git a/src/tests/dlt-test-multi-process.c b/src/tests/dlt-test-multi-process.c new file mode 100755 index 0000000..d11cd1f --- /dev/null +++ b/src/tests/dlt-test-multi-process.c @@ -0,0 +1,384 @@ +/* + * DLT multi process tester + * @licence app begin@ + * + * Copyright (C) 2011, BMW AG - Lassi Marttala Lassi Marttala <Lassi.LM.Marttala@partner.bmw.de> + * + * This program is free software; you can redistribute it and/or modify it under the terms of the + * GNU Lesser General Public License, version 2.1, as published by the Free Software Foundation. + * 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 Lesser General + * Public License, version 2.1, for more details. + * + * You should have received a copy of the GNU Lesser General Public License, version 2.1, along + * with this program; if not, see <http://www.gnu.org/licenses/lgpl-2.1.html>. + * + * Note that the copyright holders assume that the GNU Lesser General Public License, version 2.1, may + * also be applicable to programs even in cases in which the program is not a library in the technical sense. + * + * Linking DLT statically or dynamically with other modules is making a combined work based on DLT. You may + * license such other modules under the GNU Lesser General Public License, version 2.1. If you do not want to + * license your linked modules under the GNU Lesser General Public License, version 2.1, you + * may use the program under the following exception. + * + * As a special exception, the copyright holders of DLT give you permission to combine DLT + * with software programs or libraries that are released under any license unless such a combination is not + * permitted by the license of such a software program or library. You may copy and distribute such a + * system following the terms of the GNU Lesser General Public License, version 2.1, including this + * special exception, for DLT and the licenses of the other code concerned. + * + * Note that people who make modified versions of DLT are not obligated to grant this special exception + * for their modified versions; it is their choice whether to do so. The GNU Lesser General Public License, + * version 2.1, gives permission to release a modified version without this exception; this exception + * also makes it possible to release a modified version which carries forward this exception. + * + * @licence end@ + */ + +/******************************************************************************* +** ** +** SRC-MODULE: dlt-test-multi-process.c ** +** ** +** TARGET : linux ** +** ** +** PROJECT : DLT ** +** ** +** AUTHOR : Lassi Marttala Lassi.LM.Marttala@partner.bmw.de ** +** ** +** PURPOSE : Stress test timing using multiple processes ** +** ** +** REMARKS : Requires POSIX fork() ** +** ** +** PLATFORM DEPENDANT [yes/no]: yes ** +** ** +** TO BE CHANGED BY USER [yes/no]: no ** +** ** +*******************************************************************************/ +#include <stdlib.h> +#include <stdio.h> +#include <ctype.h> +#include <unistd.h> +#include <limits.h> +#include <signal.h> +#include <errno.h> +#include <pthread.h> +#include <sys/wait.h> + +#include "dlt.h" +#include "dlt_common.h" +#include "dlt-test-multi-process.h" + +// Constants +#define MAX_PROCS 100 +#define MAX_THREADS 100 + +// Structs +typedef struct { + int nmsgs; // Number of messages to send + int nprocs; // Number of processes to start + int nthreads; // Number of threads to start + int delay; // Delay between logs messages for each process + int delay_fudge; // Fudge the delay by 0-n to cause desynchronization +} s_parameters; + +typedef struct { + s_parameters params; + DltContext ctx; +} s_thread_data; + +// Forward declarations +void quit_handler(int signum); +void cleanup(); +void do_forks(s_parameters params); +void run_threads(s_parameters params); +void do_logging(s_thread_data *data); +int wait_for_death(); + +// State information +volatile sig_atomic_t in_handler = 0; + +// Globals for cleanup from main and signal handler +pid_t pids[MAX_PROCS]; +int pidcount = 0; + +/** + * Print instructions. + */ +void usage(char *prog_name) +{ + char version[255]; + dlt_get_version(version); + + printf("Usage: %s [options]\n", prog_name); + printf("Test application for stress testing the daemon with multiple processes and threads.\n"); + printf("%s\n", version); + printf("Options:\n"); + printf(" -m number Number of messages per thread to send.\n"); + printf(" -p number Number of processes to start. Max %d.\n", MAX_PROCS); + printf(" -t number Number of threads per process. Max %d.\n", MAX_THREADS); + printf(" -d delay Delay in milliseconds to wait between log messages.\n"); + printf(" -f delay Random fudge in milliseconds to add to delay.\n"); +} + +/** + * Set nice default values for parameters + */ +void init_params(s_parameters * params) { + params->nmsgs = 100; + params->nprocs = 10; + params->nthreads = 2; + params->delay = 1000; + params->delay_fudge = 100; +} + +/** + * Read the command line and modify parameters + */ +int read_cli(s_parameters *params, int argc, char **argv) +{ + int c; + opterr = 0; + while ((c = getopt (argc, argv, "m:p:t:d:f:")) != -1) + { + switch(c) + { + case 'm': + params->nmsgs = atoi(optarg); + break; + case 'p': + params->nprocs = atoi(optarg); + if(params->nprocs > MAX_PROCS) + { + fprintf(stderr, "Too many processes selected.\n"); + return -1; + } + break; + case 't': + params->nthreads = atoi(optarg); + if(params->nprocs > MAX_PROCS) + { + fprintf(stderr, "Too many threads selected.\n"); + return -1; + } + break; + case 'd': + params->delay = atoi(optarg); + break; + case 'f': + params->delay_fudge = atoi(optarg); + break; + case '?': + if(optopt == 'n' || optopt == 'd' || optopt == 'f') + { + fprintf(stderr, "Option -%c requires an argument.\n", optopt); + } + else if(isprint(optopt)) + { + fprintf(stderr, "Unknown option '-%c'.\n", optopt); + } + else + { + fprintf(stderr, "Unknown option character '\\x%x'.\n", optopt); + } + return -1; + break; + default: + abort(); + } + } + return 0; +} + +/** + * Entry point + */ +int main(int argc, char **argv) +{ + // Prepare parameters + s_parameters params; + init_params(¶ms); + if(read_cli(¶ms, argc, argv) != 0) { + usage(argv[0]); + exit(-1); + } + + // Launch the child processes + do_forks(params); + + // Register signal handlers + if(signal(SIGINT, quit_handler) == SIG_IGN) + signal(SIGINT, SIG_IGN); // C-c + if(signal(SIGHUP, quit_handler) == SIG_IGN) + signal(SIGHUP, SIG_IGN); // Terminal closed + if(signal(SIGTERM, quit_handler) == SIG_IGN) + signal(SIGTERM, SIG_IGN); // kill (nice) + + printf("Setup done. Listening. My pid: %d\n", getpid()); + fflush(stdout); + + int err = wait_for_death(); + cleanup(); + return err; +} + +/** + * Start the child processes + */ + +void do_forks(s_parameters params) +{ + int i; + + // Launch child processes + for(i=0;i<params.nprocs;i++) + { + pid_t pid = fork(); + switch(pid) + { + case -1: // An error occured + if(errno == EAGAIN) + { + fprintf(stderr, "Could not allocate resources for child process.\n"); + cleanup(); + abort(); + } + if(errno == ENOMEM) + { + fprintf(stderr, "Could not allocate memory for child process' kernel structure.\n"); + cleanup(); + abort(); + } + case 0: // Child process, start threads + run_threads(params); + break; + default: // Parent process, store the childs pid + pids[pidcount++] = pid; + break; + } + } +} + +/** + * Clean up the child processes. + * Reraise signal to default handler. + */ +void quit_handler(int signum) +{ + if(in_handler) + raise(signum); + in_handler = 1; + + cleanup(); + + signal(signum, SIG_DFL); + raise(signum); +} + +/** + * Ask the child processes to die + */ +void cleanup() +{ + int i; + for(i=0;i<pidcount;i++) + { + kill(pids[i], SIGINT); + } +} + +/** + * Generate the next sleep time + */ +time_t mksleep_time(int delay, int fudge) +{ + return (delay+rand()%fudge)*1000; +} + +/** + * Open logging channel and proceed to spam messages + */ +void do_logging(s_thread_data *data) +{ + //__asm__ ("int $0xCC"); + int msgs_left = data->params.nmsgs; + pid_t mypid = getpid(); + + + srand(mypid); + + while(msgs_left-- > 0) + { + DLT_LOG(data->ctx, DLT_LOG_INFO, DLT_STRING(PAYLOAD_DATA)); + usleep(mksleep_time(data->params.delay, data->params.delay_fudge)); + } +} + +/** + * Start the threads and wait for them to return. + */ +void run_threads(s_parameters params) +{ + DltContext mycontext; + pthread_t thread[params.nthreads]; + s_thread_data thread_data; + char ctid[5]; + int i; + + srand(getpid()); + + DLT_REGISTER_APP(DMPT_NAME,"DLT daemon multi process test."); + sprintf(ctid,"%.2x", rand() & 0x0000ffff); + DLT_REGISTER_CONTEXT(mycontext, ctid, "Child in dlt-test-multi-process"); + + thread_data.params = params; + thread_data.ctx = mycontext; + + for(i=0;i<params.nthreads;i++) + { + if(pthread_create(&(thread[i]), NULL, (void *) &do_logging, &thread_data) != 0) + { + printf("Error creating thread.\n"); + abort(); + } + } + + for(i=0;i<params.nthreads;i++) + { + pthread_join(thread[i], NULL); + } + + DLT_UNREGISTER_CONTEXT(mycontext); + DLT_UNREGISTER_APP(); + // We can exit now + exit(0); +} + +/** + * Wait for child processes to complete their work. + */ +int wait_for_death() +{ + int pids_left = pidcount; + while(pids_left > 0) + { + int status; + pid_t w = waitpid(WAIT_ANY, &status, 0); + if(status < 0) + { + return -1; + } + else + { + int i; + for(i=0;i<pidcount;i++) + { + if(pids[i] == w) + { + pids_left--; + break; + } + } + } + } + return 0; +} diff --git a/src/tests/dlt-test-multi-process.h b/src/tests/dlt-test-multi-process.h new file mode 100644 index 0000000..304b6fb --- /dev/null +++ b/src/tests/dlt-test-multi-process.h @@ -0,0 +1,45 @@ +/* + * DLT multi process tester + * @licence app begin@ + * + * Copyright (C) 2011, BMW AG - Lassi Marttala <Lassi.LM.Marttala@partner.bmw.de> + * + * This program is free software; you can redistribute it and/or modify it under the terms of the + * GNU Lesser General Public License, version 2.1, as published by the Free Software Foundation. + * 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 Lesser General + * Public License, version 2.1, for more details. + * + * You should have received a copy of the GNU Lesser General Public License, version 2.1, along + * with this program; if not, see <http://www.gnu.org/licenses/lgpl-2.1.html>. + * + * Note that the copyright holders assume that the GNU Lesser General Public License, version 2.1, may + * also be applicable to programs even in cases in which the program is not a library in the technical sense. + * + * Linking DLT statically or dynamically with other modules is making a combined work based on DLT. You may + * license such other modules under the GNU Lesser General Public License, version 2.1. If you do not want to + * license your linked modules under the GNU Lesser General Public License, version 2.1, you + * may use the program under the following exception. + * + * As a special exception, the copyright holders of DLT give you permission to combine DLT + * with software programs or libraries that are released under any license unless such a combination is not + * permitted by the license of such a software program or library. You may copy and distribute such a + * system following the terms of the GNU Lesser General Public License, version 2.1, including this + * special exception, for DLT and the licenses of the other code concerned. + * + * Note that people who make modified versions of DLT are not obligated to grant this special exception + * for their modified versions; it is their choice whether to do so. The GNU Lesser General Public License, + * version 2.1, gives permission to release a modified version without this exception; this exception + * also makes it possible to release a modified version which carries forward this exception. + * + * @licence end@ + */ + +#ifndef DLT_TEST_MULTI_PROCESS_H_ +#define DLT_TEST_MULTI_PROCESS_H_ + +#define DMPT_NAME "DMPT" +#define PAYLOAD_DATA "qwertyuiopasdfghjklzxcvbnmQWERTYUIOPASDFGHJKLZXCVBM1234567890" +#define ECUID "ECU1" + +#endif /* DLT_TEST_MULTI_PROCESS_H_ */ |