summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authoreBardieCT <40671803+eBardieCT@users.noreply.github.com>2018-09-25 14:49:29 +0100
committerChristoph Lipka <clipka@users.noreply.github.com>2018-09-25 15:49:29 +0200
commit10a2c7673d2ae9d9ef8d59a417b6554881531a66 (patch)
treebfb7d7efa60df8213db326823112f05da1098468
parent0f6d2ee216bed228676e6ea8f33b8bfbf6cf1880 (diff)
downloadDLT-daemon-10a2c7673d2ae9d9ef8d59a417b6554881531a66.tar.gz
Add dlt-sortbytimestamp utility plus documentation (#73)
* Add dlt-sortbytimestamp utility plus documentation Add a commandline utility to sort a DLT file by timestamp. By default a DLT file's messages are in the order they were received by the logger. This is not ideal for tracing problems on systems with multi-threaded programmes running on multi-core CPUs since message reception order will not always (or even often) correspond to message creation order. The documentation deals with how to handle the problem case of DLT files containing messages from multiple boot cycles.
-rw-r--r--README.md1
-rw-r--r--automotive-dlt.spec.in2
-rw-r--r--doc/CMakeLists.txt29
-rw-r--r--doc/dlt-sortbytimestamp.1103
-rw-r--r--doc/dlt-sortbytimestamp.1.txt81
-rw-r--r--doc/dlt_book.txt2
-rw-r--r--doc/dlt_design_specification.txt2
-rw-r--r--doc/dlt_user_manual.txt18
-rw-r--r--src/console/CMakeLists.txt7
-rw-r--r--src/console/dlt-sortbytimestamp.c418
10 files changed, 649 insertions, 14 deletions
diff --git a/README.md b/README.md
index d78834e..c7ba698 100644
--- a/README.md
+++ b/README.md
@@ -38,6 +38,7 @@ See INSTALL regarding doxygen API documentation generation.
- dlt-system(1)
- dlt-system.conf(5)
- dlt-convert(1)
+- dlt-sortbytimestamp(1)
- dlt-receive(1)
- dlt-logstorage-ctrl(1)
- dlt-dbus (1) TBD
diff --git a/automotive-dlt.spec.in b/automotive-dlt.spec.in
index ec5fe53..8848095 100644
--- a/automotive-dlt.spec.in
+++ b/automotive-dlt.spec.in
@@ -115,6 +115,7 @@ rm -rf $RPM_BUILD_ROOT
%{_libdir}/libdlt.so
%{_bindir}/dlt-system
%{_bindir}/dlt-convert
+%{_bindir}/dlt-sortbytimestamp
%{_bindir}/dlt-receive
%{_bindir}/dlt-adaptor-stdin
%{_bindir}/dlt-adaptor-udp
@@ -137,6 +138,7 @@ rm -rf $RPM_BUILD_ROOT
%files doc
@PACKAGE_DOC@%{_mandir}/man1/dlt-convert.1.gz
+@PACKAGE_DOC@%{_mandir}/man1/dlt-sortbytimestamp.1.gz
@PACKAGE_DOC@%{_mandir}/man1/dlt-daemon.1.gz
@PACKAGE_DOC@%{_mandir}/man1/dlt-receive.1.gz
@PACKAGE_DOC@%{_mandir}/man1/dlt-system.1.gz
diff --git a/doc/CMakeLists.txt b/doc/CMakeLists.txt
index d04bf8d..263dbe0 100644
--- a/doc/CMakeLists.txt
+++ b/doc/CMakeLists.txt
@@ -19,12 +19,12 @@ if(WITH_DOC)
find_package(Doxygen)
configure_file(${CMAKE_SOURCE_DIR}/doc/doxygen.cfg.cmake ${CMAKE_BINARY_DIR}/doc/doxygen.cfg @ONLY)
-
+
add_custom_target (doc ALL
COMMAND ${DOXYGEN_EXECUTABLE} ${CMAKE_BINARY_DIR}/doc/doxygen.cfg
WORKING_DIRECTORY ${CMAKE_BINARY_DIR}/doc
)
-
+
add_custom_target (doc-manuals ALL
COMMAND mkdir -p ${CMAKE_BINARY_DIR}/doc/manuals
COMMAND mkdir -p ${CMAKE_BINARY_DIR}/doc/manuals/images
@@ -40,6 +40,7 @@ if(WITH_DOC)
COMMAND asciidoc -a TOC1 -o ${CMAKE_BINARY_DIR}/doc/manuals/dlt-system.1.html ${CMAKE_SOURCE_DIR}/doc/dlt-system.1.txt
COMMAND asciidoc -a TOC1 -o ${CMAKE_BINARY_DIR}/doc/manuals/dlt-receive.1.html ${CMAKE_SOURCE_DIR}/doc/dlt-receive.1.txt
COMMAND asciidoc -a TOC1 -o ${CMAKE_BINARY_DIR}/doc/manuals/dlt-convert.1.html ${CMAKE_SOURCE_DIR}/doc/dlt-convert.1.txt
+ COMMAND asciidoc -a TOC1 -o ${CMAKE_BINARY_DIR}/doc/manuals/dlt-sortbytimestamp.1.html ${CMAKE_SOURCE_DIR}/doc/dlt-sortbytimestamp.1.txt
COMMAND asciidoc -a TOC1 -o ${CMAKE_BINARY_DIR}/doc/manuals/dlt.conf.5.html ${CMAKE_SOURCE_DIR}/doc/dlt.conf.5.txt
COMMAND asciidoc -a TOC1 -o ${CMAKE_BINARY_DIR}/doc/manuals/dlt-system.conf.5.html ${CMAKE_SOURCE_DIR}/doc/dlt-system.conf.5.txt
COMMAND asciidoc -a TOC1 -o ${CMAKE_BINARY_DIR}/doc/manuals/dlt_book.html ${CMAKE_SOURCE_DIR}/doc/dlt_book.txt
@@ -58,12 +59,13 @@ if(WITH_DOC)
COMMAND a2x --doctype manpage --format manpage ${CMAKE_SOURCE_DIR}/doc/dlt-system.1.txt
COMMAND a2x --doctype manpage --format manpage ${CMAKE_SOURCE_DIR}/doc/dlt-receive.1.txt
COMMAND a2x --doctype manpage --format manpage ${CMAKE_SOURCE_DIR}/doc/dlt-convert.1.txt
+ COMMAND a2x --doctype manpage --format manpage ${CMAKE_SOURCE_DIR}/doc/dlt-sortbytimestamp.1.txt
COMMAND a2x --doctype manpage --format manpage ${CMAKE_SOURCE_DIR}/doc/dlt.conf.5.txt
COMMAND a2x --doctype manpage --format manpage ${CMAKE_SOURCE_DIR}/doc/dlt-system.conf.5.txt
COMMAND a2x --doctype manpage --format manpage ${CMAKE_SOURCE_DIR}/doc/dlt-logstorage-ctrl.1.txt
COMMAND a2x --doctype manpage --format manpage ${CMAKE_SOURCE_DIR}/doc/dlt-passive-node-ctrl.1.txt
)
-
+
endif(WITH_DOC)
if(WITH_MAN)
@@ -73,18 +75,19 @@ if(WITH_MAN)
PATHS /bin
/usr/bin
/usr/local/bin)
-
+
if(NOT GZIP_TOOL)
MESSAGE(FATAL_ERROR "Could not find gzip for man page compression.")
endif(NOT GZIP_TOOL)
-
+
set(MAN_SRC_DIR ${CMAKE_CURRENT_SOURCE_DIR})
set(MAN_BUILD_DIR ${CMAKE_BINARY_DIR}/doc)
-
+
set(MAN_SRC
${MAN_SRC_DIR}/dlt.conf.5
${MAN_SRC_DIR}/dlt-system.conf.5
${MAN_SRC_DIR}/dlt-convert.1
+ ${MAN_SRC_DIR}/dlt-sortbytimestamp.1
${MAN_SRC_DIR}/dlt-daemon.1
${MAN_SRC_DIR}/dlt-receive.1
${MAN_SRC_DIR}/dlt-system.1
@@ -94,6 +97,7 @@ if(WITH_MAN)
${MAN_BUILD_DIR}/dlt.conf.5
${MAN_BUILD_DIR}/dlt-system.conf.5
${MAN_BUILD_DIR}/dlt-convert.1
+ ${MAN_BUILD_DIR}/dlt-sortbytimestamp.1
${MAN_BUILD_DIR}/dlt-daemon.1
${MAN_BUILD_DIR}/dlt-receive.1
${MAN_BUILD_DIR}/dlt-system.1
@@ -103,37 +107,40 @@ if(WITH_MAN)
${MAN_BUILD_DIR}/dlt.conf.5.gz
${MAN_BUILD_DIR}/dlt-system.conf.5.gz
${MAN_BUILD_DIR}/dlt-convert.1.gz
+ ${MAN_BUILD_DIR}/dlt-sortbytimestamp.1.gz
${MAN_BUILD_DIR}/dlt-daemon.1.gz
${MAN_BUILD_DIR}/dlt-receive.1.gz
${MAN_BUILD_DIR}/dlt-system.1.gz
${MAN_BUILD_DIR}/dlt-logstorage-ctrl.1.gz
${MAN_BUILD_DIR}/dlt-passive-node-ctrl.1.gz)
-
+
foreach(MAN ${MAN_SRC})
execute_process(COMMAND ${CMAKE_COMMAND} -E copy ${MAN} ${MAN_BUILD_DIR})
endforeach(MAN)
-
+
add_custom_target(compress_man ALL
COMMAND ${GZIP_TOOL} -c ${MAN_BUILD_DIR}/dlt.conf.5 > ${MAN_BUILD_DIR}/dlt.conf.5.gz
COMMAND ${GZIP_TOOL} -c ${MAN_BUILD_DIR}/dlt-system.conf.5 > ${MAN_BUILD_DIR}/dlt-system.conf.5.gz
COMMAND ${GZIP_TOOL} -c ${MAN_BUILD_DIR}/dlt-convert.1 > ${MAN_BUILD_DIR}/dlt-convert.1.gz
+ COMMAND ${GZIP_TOOL} -c ${MAN_BUILD_DIR}/dlt-sortbytimestamp.1 > ${MAN_BUILD_DIR}/dlt-sortbytimestamp.1.gz
COMMAND ${GZIP_TOOL} -c ${MAN_BUILD_DIR}/dlt-daemon.1 > ${MAN_BUILD_DIR}/dlt-daemon.1.gz
COMMAND ${GZIP_TOOL} -c ${MAN_BUILD_DIR}/dlt-receive.1 > ${MAN_BUILD_DIR}/dlt-receive.1.gz
COMMAND ${GZIP_TOOL} -c ${MAN_BUILD_DIR}/dlt-system.1 > ${MAN_BUILD_DIR}/dlt-system.1.gz
COMMAND ${GZIP_TOOL} -c ${MAN_BUILD_DIR}/dlt-logstorage-ctrl.1 > ${MAN_BUILD_DIR}/dlt-logstorage-ctrl.1.gz
COMMAND ${GZIP_TOOL} -c ${MAN_BUILD_DIR}/dlt-passive-node-ctrl.1 > ${MAN_BUILD_DIR}/dlt-passive-node-ctrl.1.gz)
-
+
# If user has not set the base dir for man pages, use a default location
set(MAN_INSTALL_DIR ${CMAKE_INSTALL_PREFIX}/share/man)
-
+
install(FILES
${MAN_BUILD_DIR}/dlt.conf.5.gz
${MAN_BUILD_DIR}/dlt-system.conf.5.gz
DESTINATION ${MAN_INSTALL_DIR}/man5
)
-
+
install(FILES
${MAN_BUILD_DIR}/dlt-convert.1.gz
+ ${MAN_BUILD_DIR}/dlt-sortbytimestamp.1.gz
${MAN_BUILD_DIR}/dlt-daemon.1.gz
${MAN_BUILD_DIR}/dlt-receive.1.gz
${MAN_BUILD_DIR}/dlt-system.1.gz
diff --git a/doc/dlt-sortbytimestamp.1 b/doc/dlt-sortbytimestamp.1
new file mode 100644
index 0000000..7f0915f
--- /dev/null
+++ b/doc/dlt-sortbytimestamp.1
@@ -0,0 +1,103 @@
+'\" t
+.\" Title: dlt-sortbytimestamp
+.\" Author: [see the "AUTHOR" section]
+.\" Generator: DocBook XSL Stylesheets v1.79.1 <http://docbook.sf.net/>
+.\" Date: 07/17/2018
+.\" Manual: \ \&
+.\" Source: \ \&
+.\" Language: English
+.\"
+.TH "DLT\-SORTBYTIMESTAMP" "1" "07/17/2018" "\ \&" "\ \&"
+.\" -----------------------------------------------------------------
+.\" * Define some portability stuff
+.\" -----------------------------------------------------------------
+.\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+.\" http://bugs.debian.org/507673
+.\" http://lists.gnu.org/archive/html/groff/2009-02/msg00013.html
+.\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+.ie \n(.g .ds Aq \(aq
+.el .ds Aq '
+.\" -----------------------------------------------------------------
+.\" * set default formatting
+.\" -----------------------------------------------------------------
+.\" disable hyphenation
+.nh
+.\" disable justification (adjust text to left margin only)
+.ad l
+.\" -----------------------------------------------------------------
+.\" * MAIN CONTENT STARTS HERE *
+.\" -----------------------------------------------------------------
+.SH "NAME"
+dlt-sortbytimestamp \- Re\-order DLT Logging files according to message creation time
+.SH "SYNOPSIS"
+.sp
+\fBdlt\-sortbytimestamp\fR [\-h] [\-v] [\-c] [\-f filterfile] [\-b number] [\-e number] dltfile_in dltfile_out
+.SH "DESCRIPTION"
+.sp
+By default messages in DLT files are ordered according to the time the logger received them\&. This can unhelpful when tracing a sequence of events on a busy multi\-threaded/multi\-core system, because thread pre\-emption combined with multiple processes attempting to log messages simultaneously means that the order in which the messages are received may vary significantly from the order in which they were created\&.
+.sp
+\fBdlt\-sortbytimestamp\fR re\-orders a DLT input file\(cqs messages according their creation timestamp, and writes them to an output DLT file\&.
+.SH "IMPORTANT NOTE"
+.sp
+Message timestamps are recorded relative to boot time\&. DLT files can contain messages from more than one reboot cycle\&. Because timestamping is reset to zero at each boot, simply running \fBdlt\-sortbytimestamp\fR against a multi\-boot\-cycle DLT input file will produce a tangled mess\&.
+.sp
+Use the \fB\-b\fR and/or \fB\-e\fR options to specify a range of messages within a single reboot cycle and all will be well\&.
+.sp
+Hint: use \fBdlt\-viewer\fR to ascertain the endpoints of the range in question\&.
+.SH "OPTIONS"
+.PP
+\fB\-h\fR
+.RS 4
+Display a short help text\&.
+.RE
+.PP
+\fB\-v\fR
+.RS 4
+Verbose mode\&. Repeat to give more information\&.
+.RE
+.PP
+\fB\-c\fR
+.RS 4
+Count number of messages\&.
+.RE
+.PP
+\fB\-f\fR
+.RS 4
+Enable filtering of messages\&. Incompatible with range options\&.
+.RE
+.PP
+\fB\-b\fR
+.RS 4
+First message to be handled\&. Zero based index\&.
+.RE
+.PP
+\fB\-e\fR
+.RS 4
+Last message to be handled\&. Zero based index\&.
+.RE
+.SH "EXAMPLES"
+.PP
+Sort an entire file by message timestamp
+.RS 4
+\fBdlt\-sortbytimestamp input\&.dlt output\&.dlt\fR
+.RE
+.PP
+Sort a specific range, e\&.g\&. from message 1,000,000 to message 1,500,000 from a file called input\&.dlt and store the result in a file called output\&.dlt
+.RS 4
+\fBdlt\-sortbytimestamp \-b 1000000 \-e 1500000 input\&.dlt output\&.dlt\fR
+.RE
+.SH "EXIT STATUS"
+.sp
+Non zero is returned in case of failure\&.
+.SH "AUTHOR"
+.sp
+Jonathan Sambrook (jonathan\&.sambrook (at) codethink\&.co\&.uk) Alexander Wenzel (alexander\&.aw\&.wenzel (at) bmw\&.de)
+.SH "COPYRIGHT"
+.sp
+Copyright \(co 2018 Codethink Ltd\&. Copyright \(co 2015 BMW AG\&. License MPL\-2\&.0: Mozilla Public License version 2\&.0 http://mozilla\&.org/MPL/2\&.0/\&.
+.SH "RESOURCES"
+.sp
+Main web site: http://projects\&.genivi\&.org/diagnostic\-log\-trace Mailinglist: https://lists\&.genivi\&.org/mailman/listinfo/genivi\-diagnostic\-log\-and\-trace
+.SH "SEE ALSO"
+.sp
+dlt\-convert(1) dlt\-daemon(1)
diff --git a/doc/dlt-sortbytimestamp.1.txt b/doc/dlt-sortbytimestamp.1.txt
new file mode 100644
index 0000000..cb92051
--- /dev/null
+++ b/doc/dlt-sortbytimestamp.1.txt
@@ -0,0 +1,81 @@
+DLT-SORTBYTIMESTAMP(1)
+======================
+:doctype: manpage
+
+NAME
+----
+dlt-sortbytimestamp - Re-order DLT Logging files according to message creation time
+
+SYNOPSIS
+--------
+*dlt-sortbytimestamp* [-h] [-v] [-c] [-f filterfile] [-b number] [-e number] dltfile_in dltfile_out
+
+DESCRIPTION
+-----------
+By default messages in DLT files are ordered according to the time the logger received them. This can unhelpful when tracing a sequence of events on a busy multi-threaded/multi-core system, because thread pre-emption combined with multiple processes attempting to log messages simultaneously means that the order in which the messages are received may vary significantly from the order in which they were created.
+
+*dlt-sortbytimestamp* re-orders a DLT input file's messages according their creation timestamp, and writes them to an output DLT file.
+
+IMPORTANT NOTE
+--------------
+Message timestamps are recorded relative to boot time. DLT files can contain messages from more than one reboot cycle. Because timestamping is reset to zero at each boot, simply running *dlt-sortbytimestamp* against a multi-boot-cycle DLT input file will produce a tangled mess.
+
+Use the *-b* and/or *-e* options to specify a range of messages within a single reboot cycle and all will be well.
+
+Hint: use *dlt-viewer* to ascertain the endpoints of the range in question.
+
+OPTIONS
+-------
+*-h*::
+ Display a short help text.
+
+*-v*::
+ Verbose mode. Repeat to give more information.
+
+*-c*::
+ Count number of messages.
+
+*-f*::
+ Enable filtering of messages. Incompatible with range options.
+
+*-b*::
+ First message to be handled. Zero based index.
+
+*-e*::
+ Last message to be handled. Zero based index.
+
+EXAMPLES
+--------
+
+Sort an entire file by message timestamp::
+ *dlt-sortbytimestamp input.dlt output.dlt*
+
+Sort a specific range, e.g. from message 1,000,000 to message 1,500,000 from a file called input.dlt and store the result in a file called output.dlt::
+ *dlt-sortbytimestamp -b 1000000 -e 1500000 input.dlt output.dlt*
+
+
+EXIT STATUS
+-----------
+Non zero is returned in case of failure.
+
+AUTHOR
+------
+Jonathan Sambrook (jonathan.sambrook (at) codethink.co.uk)
+Alexander Wenzel (alexander.aw.wenzel (at) bmw.de)
+
+COPYRIGHT
+---------
+Copyright (C) 2018 Codethink Ltd.
+Copyright (C) 2015 BMW AG.
+License MPL-2.0: Mozilla Public License version 2.0 <http://mozilla.org/MPL/2.0/>.
+
+RESOURCES
+---------
+Main web site: <http://projects.genivi.org/diagnostic-log-trace> +
+Mailinglist: <https://lists.genivi.org/mailman/listinfo/genivi-diagnostic-log-and-trace>
+
+SEE ALSO
+--------
+dlt-convert(1)
+dlt-daemon(1)
+
diff --git a/doc/dlt_book.txt b/doc/dlt_book.txt
index 1026bb4..8a2c91e 100644
--- a/doc/dlt_book.txt
+++ b/doc/dlt_book.txt
@@ -78,6 +78,8 @@ include::dlt-system.conf.5.txt[]
include::dlt-convert.1.txt[]
+include::dlt-sortbytimestamp.1.txt[]
+
include::dlt-receive.1.txt[]
include::dlt-logstorage-ctrl.1.txt[]
diff --git a/doc/dlt_design_specification.txt b/doc/dlt_design_specification.txt
index 4d52a2a..6d1bdf4 100644
--- a/doc/dlt_design_specification.txt
+++ b/doc/dlt_design_specification.txt
@@ -531,7 +531,7 @@ As this document has the focus on the DLT Daemon and the DLT user library, only
| src | | Source Code
| src | shared | Shared source code (between DLT daemon and DLT user library)
| src | adaptor | Adaptors to DLT daemon:dlt-adaptor-stdin (for connection over stdin) dlt-adaptor-udp (for connection over UDP)
-| src | console | Console utilities: dlt-receive and dlt-convert
+| src | console | Console utilities: dlt-receive, dlt-convert, and dlt-sortbytimestamp
| src | daemon | DLT Daemon
| src | example | Examples for usage of the DLT user library:dlt-example-user (Macro IF) anddlt-example-user-func (Function IF) andwintestclient (MS Windows based test client)
| src | lib | DLT library functions
diff --git a/doc/dlt_user_manual.txt b/doc/dlt_user_manual.txt
index 8b937b1..c8f444e 100644
--- a/doc/dlt_user_manual.txt
+++ b/doc/dlt_user_manual.txt
@@ -36,6 +36,7 @@ The SW components of DLT:
* dlt-adaptor-stdin
* dlt-adaptor-udp
* dlt-convert
+* dlt-sortbytimestamp
* dlt-receive
* dlt-dbus
* dlt-kpi
@@ -137,12 +138,13 @@ See Manpage dlt-system(1).
See Manpage dlt-system.conf(5).
== DLT command line tools
-Three command line tools are provided together with DLT daemon implementation.
+Four command line tools are provided together with DLT daemon implementation.
These tools are:
* Data logger: dlt-receive
* Converter: dlt-convert
+* Sorter: dlt-sortbytimestamp
* Configuration: dlt-control (planned)
@@ -162,6 +164,20 @@ The dlt-convert console utility is used to read DLT files, print DLT messages in
==== Command line interface
See Manpage dlt-convert(1).
+=== dlt-sortbytimestamp
+
+==== Overview
+By default messages in DLT files are ordered according to the time the logger received them. This can unhelpful when tracing a sequence of events on a busy multi-threaded/multi-core system, because thread pre-emption combined with multiple processes attempting to log messages simultaneously means that the order in which the messages are received may vary significantly from the order in which they were created.
+
+The dlt-sortbytimestamp console utility is used to re-order the messages in DLT files, sorting them according to when the messages were created.
+
+Filters can be used to filter messages OR a range of messages to be processed can specified.
+
+Ranges are essential when processing a DLT file covering more than a single reboot cycle. This is because message timestamps are recorded relative to boot time and thus timestamping is reset to zero at each boot. Events from different boot cycles will have differing receive times, but may have identical boot relative timestamps. Using *dlt-sortbytimestamp* to sort such a DLT file will result in a tangled mess. Use ranges to avoid this. Use *dlt-viewer* to ascertain the start and end message indices of the desired range.
+
+==== Command line interface
+See Manpage dlt-sortbytimestamp(1).
+
== DLT adaptors
The DLT adaptors are used to interface legacy linux applications with the DLT daemon. Therefore, there are two adaptors:
diff --git a/src/console/CMakeLists.txt b/src/console/CMakeLists.txt
index 0fa2a1b..c2e5586 100644
--- a/src/console/CMakeLists.txt
+++ b/src/console/CMakeLists.txt
@@ -15,6 +15,11 @@
# @licence end@
#######
+set(dlt_sortbytimestamp_SRCS dlt-sortbytimestamp.c)
+add_executable(dlt-sortbytimestamp ${dlt_sortbytimestamp_SRCS} ${dlt_most_SRCS})
+target_link_libraries(dlt-sortbytimestamp dlt ${EXPAT_LIBRARIES})
+set_target_properties(dlt-sortbytimestamp PROPERTIES LINKER_LANGUAGE C)
+
set(dlt_convert_SRCS dlt-convert.c)
add_executable(dlt-convert ${dlt_convert_SRCS} ${dlt_most_SRCS})
target_link_libraries(dlt-convert dlt ${EXPAT_LIBRARIES})
@@ -37,6 +42,6 @@ set(dlt_passive_node_ctrl_SRCS dlt-passive-node-ctrl.c dlt-control-common.c)
add_executable(dlt-passive-node-ctrl ${dlt_passive_node_ctrl_SRCS} ${dlt_most_SRCS})
target_link_libraries(dlt-passive-node-ctrl dlt ${EXPAT_LIBRARIES})
-install(TARGETS dlt-convert dlt-receive dlt-control dlt-passive-node-ctrl
+install(TARGETS dlt-sortbytimestamp dlt-convert dlt-receive dlt-control dlt-passive-node-ctrl
RUNTIME DESTINATION bin
COMPONENT base)
diff --git a/src/console/dlt-sortbytimestamp.c b/src/console/dlt-sortbytimestamp.c
new file mode 100644
index 0000000..6d1d590
--- /dev/null
+++ b/src/console/dlt-sortbytimestamp.c
@@ -0,0 +1,418 @@
+/*
+ * @licence app begin@
+ * SPDX license identifier: MPL-2.0
+ *
+ * Copyright (C) 2018, Codethink Ltd.
+ * Copyright (C) 2011-2015, BMW AG
+ *
+ * This file is part of GENIVI Project DLT - Diagnostic Log and Trace.
+ *
+ * This Source Code Form is subject to the terms of the
+ * Mozilla Public License (MPL), v. 2.0.
+ * If a copy of the MPL was not distributed with this file,
+ * You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * For further information see http://www.genivi.org/.
+ * @licence end@
+ */
+
+/*!
+ * \author Jonathan Sambrook <jonathan.sambrook@codethink.co.uk>
+ *
+ * \copyright Copyright © 2018 Codethink Ltd. \n
+ * Copyright © 2011-2015 BMW AG. \n
+ * License MPL-2.0: Mozilla Public License version 2.0 http://mozilla.org/MPL/2.0/.
+ *
+ * \file dlt-sortbytimestamp.cpp
+*/
+
+/*******************************************************************************
+** **
+** SRC-MODULE: dlt-sortbytimestamp.cpp **
+** **
+** TARGET : linux **
+** **
+** PROJECT : DLT **
+** **
+** AUTHOR : Jonathan Sambrook jonathasambrook@codethink.co.uk **
+** Alexander Wenzel Alexander.AW.Wenzel@bmw.de **
+** Markus Klein **
+** **
+** PURPOSE : **
+** **
+** REMARKS : **
+** **
+** PLATFORM DEPENDANT [yes/no]: yes **
+** **
+** TO BE CHANGED BY USER [yes/no]: no **
+** **
+*******************************************************************************/
+
+/*******************************************************************************
+** Author Identity **
+********************************************************************************
+** **
+** Initials Name Company **
+** -------- ------------------------- ---------------------------------- **
+** aw Alexander Wenzel BMW **
+** js Jonathan Sambrook Codethink **
+** mk Markus Klein Fraunhofer ESK **
+*******************************************************************************/
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <string.h>
+#include <ctype.h>
+#include <stdarg.h>
+#include <time.h>
+
+#include <sys/stat.h>
+#include <fcntl.h>
+
+#include <sys/uio.h> /* writev() */
+
+#include "dlt_common.h"
+
+#define DLT_VERBUFSIZE 255
+
+typedef struct sTimestampIndex {
+ int num;
+ uint32_t tmsp;
+} TimestampIndex;
+
+int verbosity = 0;
+
+/**
+ * Print information, conditional upon requested verbosity level
+ */
+void verbose(int level, char * msg, ...)
+{
+ if (level <= verbosity)
+ {
+ if (verbosity > 1) /* timestamp */
+ {
+ time_t tnow = time((time_t*)0);
+ if (tnow != -1) {
+ char * snow = ctime(&tnow);
+ /* suppress newline char */
+ snow[strlen(snow) - 1] = 0;
+ printf("%s: ", snow);
+ }
+ }
+
+ int len = strlen(msg);
+ va_list args;
+ va_start (args, msg);
+ vprintf(msg, args);
+
+ /* lines without a terminal newline aren't guaranteed to be displayed */
+ if (msg[len-1] != '\n')
+ {
+ fflush(stdout);
+ }
+ }
+}
+
+/**
+ * Comparison function for use with qsort
+ */
+int compare_index_timestamps(const void* a, const void *b)
+{
+ if (((TimestampIndex*)a)->tmsp > ((TimestampIndex*)b)->tmsp)
+ {
+ return 1;
+ }
+ else if (((TimestampIndex*)a)->tmsp == ((TimestampIndex*)b)->tmsp)
+ {
+ return 0;
+ }
+ return -1;
+}
+
+/**
+ * Write the messages in the order specified by the given index
+ */
+void write_messages(int ohandle, DltFile *file, TimestampIndex *timestamps, int message_count)
+{
+ struct iovec iov[2];
+ int bytes_written;
+
+ verbose(1, "Writing %d messages\n", message_count);
+
+ for (int i = 0; i < message_count; ++i)
+ {
+ if (0 == i % 1001 || i == message_count - 1)
+ {
+ verbose(2, "Writing message %d\r", i);
+ }
+ dlt_file_message(file,timestamps[i].num,0);
+ iov[0].iov_base = file->msg.headerbuffer;
+ iov[0].iov_len = file->msg.headersize;
+ iov[1].iov_base = file->msg.databuffer;
+ iov[1].iov_len = file->msg.datasize;
+
+ bytes_written = writev(ohandle, iov, 2);
+ if (0 > bytes_written){
+ printf("in main: writev(ohandle, iov, 2); returned an error!" );
+ dlt_file_free(file,0);
+ exit (-1);
+ }
+ }
+
+ verbose (2, "\n");
+}
+
+/**
+ * Print usage information of tool.
+ */
+void usage()
+{
+ char version[DLT_VERBUFSIZE];
+
+ dlt_get_version(version,DLT_VERBUFSIZE);
+
+ printf("Usage: dlt-sortbytimestamp [options] [commands] file_in file_out\n");
+ printf("Read DLT file, sort by timestamp and store the messages again.\n");
+ printf("Use filters to filter DLT messages.\n");
+ printf("Use range to cut DLT file. Indices are zero based.\n");
+ printf("%s \n", version);
+ printf("Commands:\n");
+ printf(" -h Usage\n");
+ printf("Options:\n");
+ printf(" -v Verbosity. Multiple uses will effect an increase in loquacity\n");
+ printf(" -c Count number of messages\n");
+ printf(" -f filename Enable filtering of messages\n");
+ printf(" -b number First message in range to be handled (default: first message)\n");
+ printf(" -e number Last message in range to be handled (default: last message)\n");
+}
+
+/**
+ * Main function of tool.
+ */
+int main(int argc, char* argv[])
+{
+ int vflag = 0;
+ int cflag = 0;
+ char *fvalue = 0;
+ char *bvalue = 0;
+ char *evalue = 0;
+ char *ivalue = 0;
+ char *ovalue = 0;
+
+ TimestampIndex *timestamp_index = 0;
+ int32_t message_count = 0;
+
+ int c;
+
+ DltFile file;
+ DltFilter filter;
+
+ int ohandle=-1;
+
+ int num, begin, end;
+
+ opterr = 0;
+
+ verbose(1, "Configuring\n");
+
+ while ((c = getopt (argc, argv, "vchf:b:e:")) != -1)
+ switch (c)
+ {
+ case 'v':
+ {
+ verbosity += 1;
+ break;
+ }
+ case 'c':
+ {
+ cflag = 1;
+ break;
+ }
+ case 'h':
+ {
+ usage();
+ return -1;
+ }
+ case 'f':
+ {
+ fvalue = optarg;
+ break;
+ }
+ case 'b':
+ {
+ bvalue = optarg;
+ break;
+ }
+ case 'e':
+ {
+ evalue = optarg;
+ break;
+ }
+ case '?':
+ {
+ if (optopt == 'f' || optopt == 'b' || optopt == 'e')
+ {
+ 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);
+ }
+ /* unknown or wrong option used, show usage information and terminate */
+ usage();
+ return -1;
+ }
+ default:
+ {
+ abort();
+ return -1;//for parasoft
+ }
+ }
+
+ /* Don't use vflag on quietest levels */
+ if (verbosity > 2)
+ {
+ vflag = 1;
+ }
+
+ verbose (1, "Initializing\n");
+
+ /* initialise structure to use DLT file */
+ dlt_file_init(&file,vflag);
+
+ /* first parse filter file if filter parameter is used */
+ if (fvalue)
+ {
+ if (bvalue || evalue)
+ {
+ fprintf(stderr,"ERROR: can't specify a range *and* filtering!\n");
+ dlt_file_free(&file,vflag);
+ return -1;
+ }
+
+ if (dlt_filter_load(&filter,fvalue,vflag) < DLT_RETURN_OK)
+ {
+ dlt_file_free(&file,vflag);
+ return -1;
+ }
+
+ dlt_file_set_filter(&file,&filter,vflag);
+ }
+
+ ivalue = argv[optind];
+
+ if (!ivalue)
+ {
+ dlt_file_free(&file,vflag);
+ fprintf(stderr,"ERROR: Need an input file!\n");
+ return -1;
+ }
+
+ ovalue = argv[optind + 1];
+
+ if (ovalue)
+ {
+ ohandle = open(ovalue,O_WRONLY|O_CREAT|O_TRUNC, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH); /* mode: wb */
+ if (ohandle == -1)
+ {
+ dlt_file_free(&file,vflag);
+ fprintf(stderr,"ERROR: Output file %s cannot be opened!\n",ovalue);
+ return -1;
+ }
+ }
+ else
+ {
+ dlt_file_free(&file,vflag);
+ fprintf(stderr,"ERROR: Need an output file!\n");
+ return -1;
+ }
+
+ verbose(1, "Loading\n");
+
+ /* load, analyse data file and create index list */
+ if (dlt_file_open(&file,ivalue,vflag) >= DLT_RETURN_OK)
+ {
+ while (dlt_file_read(&file,vflag) >= DLT_RETURN_OK)
+ {
+ }
+ }
+
+ if (cflag) {
+ if (fvalue)
+ {
+ printf("Loaded %d messages, %d after filtering.\n", file.counter_total, file.counter);
+ }
+ else
+ {
+ printf("Loaded %d messages.\n", file.counter_total);
+ }
+ }
+
+ if (bvalue)
+ {
+ begin = atoi(bvalue);
+ }
+ else
+ {
+ begin = 0;
+ }
+
+ if (evalue)
+ {
+ end = atoi(evalue);
+ }
+ else
+ {
+ end = file.counter-1;
+ }
+
+ if (begin<0 || begin>=file.counter || begin>end)
+ {
+ fprintf(stderr,"ERROR: Selected first message %d is out of range!\n",begin);
+ return -1;
+ }
+ if (end<0 || end<begin || end>=file.counter)
+ {
+ fprintf(stderr,"ERROR: Selected end message %d is out of range!\n",end);
+ return -1;
+ }
+
+ verbose(2, "Begin: %d End: %d Range: %d\n", begin, end, 1 + end - begin);
+
+ verbose(1, "Allocating memory\n");
+
+ message_count = 1 + end - begin;
+
+ timestamp_index = (TimestampIndex*)malloc(sizeof(TimestampIndex) * message_count);
+
+ if (timestamp_index == 0)
+ {
+ fprintf(stderr,"ERROR: Failed to allocate memory for message index!\n");
+ dlt_file_free(&file,vflag);
+ return -1;
+ }
+
+ verbose(1, "Filling %d entries\n", message_count);
+ for (num = begin; num <= end; num++)
+ {
+ dlt_file_message(&file,num,vflag);
+ timestamp_index[num - begin].num = num;
+ timestamp_index[num - begin].tmsp = file.msg.headerextra.tmsp;
+ }
+
+ verbose(1, "Sorting\n");
+ qsort((void*)timestamp_index, message_count, sizeof(TimestampIndex), compare_index_timestamps);
+
+ write_messages(ohandle, &file, timestamp_index, message_count);
+ close(ohandle);
+
+ verbose(1, "Tidying up.\n");
+ free(timestamp_index);
+ dlt_file_free(&file,vflag);
+ return 0;
+}