summaryrefslogtreecommitdiffstats
path: root/trace
diff options
context:
space:
mode:
authorSebastian Huber <sebastian.huber@embedded-brains.de>2019-08-29 07:53:35 +0200
committerSebastian Huber <sebastian.huber@embedded-brains.de>2019-09-03 14:59:00 +0200
commite0ac299e06c8ecd50c1c0de62a397ae0bb44bf22 (patch)
tree5b379eee98b8bc2f4df4e4faa786ee4529c3fdae /trace
parentrecord: Synchronize with RTEMS (diff)
downloadrtems-tools-e0ac299e06c8ecd50c1c0de62a397ae0bb44bf22.tar.bz2
record: Convert to C++
Formatted with: clang-format -style=Chromium -i trace/record/record-main-lttng.cc Update #3665.
Diffstat (limited to 'trace')
-rw-r--r--trace/record/record-main-lttng.c585
-rw-r--r--trace/record/record-main-lttng.cc547
-rw-r--r--trace/wscript4
3 files changed, 550 insertions, 586 deletions
diff --git a/trace/record/record-main-lttng.c b/trace/record/record-main-lttng.c
deleted file mode 100644
index 3aeafab..0000000
--- a/trace/record/record-main-lttng.c
+++ /dev/null
@@ -1,585 +0,0 @@
-/*
- * SPDX-License-Identifier: BSD-2-Clause
- *
- * Copyright (c) 2019 Ravindra Kumar Meena <rmeena840@gmail.com>
- * Copyright (C) 2018, 2019 embedded brains GmbH
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
- * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
- * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
- * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
- * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
- * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
- * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
- * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
- * POSSIBILITY OF SUCH DAMAGE.
- */
-
-#include <rtems/recorddata.h>
-#include <rtems/recordclient.h>
-
-#include <sys/queue.h>
-#include <sys/socket.h>
-
-#include <assert.h>
-#include <getopt.h>
-#include <stdbool.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <unistd.h>
-#include <inttypes.h>
-#include <fcntl.h>
-#include <errno.h>
-
-#include <netinet/in.h>
-#include <arpa/inet.h>
-
-#define CTF_MAGIC 0xC1FC1FC1
-#define TASK_RUNNING 0x0000
-#define TASK_IDLE 0x0402
-#define UUID_SIZE 16
-#define THREAD_NAME_SIZE 16
-#define THREAD_API_COUNT 3
-#define THREAD_ID_COUNT 0x10000
-#define BITS_PER_CHAR 8
-#define COMPACT_HEADER_ID 31
-
-static const struct option longopts[] = {
- { "help", 0, NULL, 'h' },
- { "host", 1, NULL, 'H' },
- { "port", 1, NULL, 'p' },
- { "input", 1, NULL, 'i' },
- { NULL, 0, NULL, 0 }
-};
-
-typedef struct {
- uint64_t ns;
- uint32_t cpu;
- rtems_record_event event;
- uint64_t data;
-} client_item;
-
-typedef struct {
- uint32_t ctf_magic;
- uint8_t uuid[ UUID_SIZE ];
- uint32_t stream_id;
- uint64_t stream_instance_id;
-} __attribute__((__packed__)) packet_header;
-
-typedef struct packet_context {
- packet_header header;
- uint64_t timestamp_begin;
- uint64_t timestamp_end;
- uint64_t content_size;
- uint64_t packet_size;
- uint64_t packet_seq_num;
- unsigned long events_discarded;
- uint32_t cpu_id;
-} __attribute__((__packed__)) packet_context;
-
-typedef struct {
- uint8_t id;
- uint32_t event_id;
- uint64_t ns;
-} __attribute__((__packed__)) event_header_compact;
-
-typedef struct {
- event_header_compact header;
- uint8_t prev_comm[ THREAD_NAME_SIZE ];
- int32_t prev_tid;
- int32_t prev_prio;
- int64_t prev_state;
- uint8_t next_comm[ THREAD_NAME_SIZE ];
- int32_t next_tid;
- int32_t next_prio;
-} __attribute__((__packed__)) sched_switch;
-
-typedef struct {
- FILE *event_stream;
- uint64_t timestamp_begin;
- uint64_t timestamp_end;
- uint64_t content_size;
- uint64_t packet_size;
- uint32_t thread_id;
- uint64_t thread_ns;
- size_t thread_name_index;
- sched_switch sched_switch;
-} per_cpu_context;
-
-typedef struct {
- rtems_record_client_context base;
- per_cpu_context per_cpu[ RTEMS_RECORD_CLIENT_MAXIMUM_CPU_COUNT ];
-
- /*
- * @brief Thread names indexed by API and object index.
- *
- * The API indices are 0 for Internal API, 1 for Classic API and 2 for
- * POSIX API.
- */
- char thread_names[ THREAD_API_COUNT ][ THREAD_ID_COUNT ][ THREAD_NAME_SIZE ];
-} client_context;
-
-static const char empty_thread_name[ THREAD_API_COUNT ];
-
-static const uint8_t uuid[] = { 0x6a, 0x77, 0x15, 0xd0, 0xb5, 0x02, 0x4c, 0x65,
-0x86, 0x78, 0x67, 0x77, 0xac, 0x7f, 0x75, 0x5a };
-
-static void usage( char **argv )
-{
- printf(
- "%s [--host=HOST] [--port=PORT] [--input=INPUT]\n"
- "\n"
- "Mandatory arguments to long options are mandatory for short options too.\n"
- " -h, --help print this help text\n"
- " -H, --host=HOST the host IPv4 address of the record server\n"
- " -p, --port=PORT the TCP port of the record server\n"
- " -i, --input=INPUT the input file\n",
- argv[ 0 ]
- );
-}
-
-static int connect_client(
- const char *host,
- uint16_t port,
- const char *input_file,
- bool input_file_flag
-)
-{
- struct sockaddr_in in_addr;
- int fd;
- int rv;
-
- fd = ( input_file_flag ) ? open( input_file, O_RDONLY ) :
- socket( PF_INET, SOCK_STREAM, 0 );
- assert( fd >= 0 );
-
- memset( &in_addr, 0, sizeof( in_addr ) );
- in_addr.sin_family = AF_INET;
- in_addr.sin_port = htons( port );
- in_addr.sin_addr.s_addr = inet_addr( host );
-
- if ( !input_file_flag ) {
- rv = connect( fd, ( struct sockaddr * ) &in_addr, sizeof( in_addr ) );
- assert( rv == 0 );
- }
-
- return fd;
-}
-
-static uint32_t get_api_index_of_id( uint32_t id )
-{
- return ( ( id >> 24 ) & 0x7 ) - 1;
-}
-
-static uint32_t get_obj_index_of_id( uint32_t id )
-{
- return id & ( THREAD_ID_COUNT - 1 );
-}
-
-static bool is_idle_task_by_api_index( uint32_t api_index )
-{
- return api_index == 0;
-}
-
-static void copy_thread_name(
- const client_context *ctx,
- const client_item *item,
- size_t api_index,
- uint8_t *dst
-)
-{
- const char *name;
-
- if ( api_index < THREAD_API_COUNT ) {
- name = ctx->thread_names[ api_index ][ get_obj_index_of_id( item->data ) ];
- } else {
- name = empty_thread_name;
- }
-
- memcpy( dst, name, THREAD_NAME_SIZE );
-
- if ( is_idle_task_by_api_index( api_index ) ) {
- /*
- * In Linux, the idle threads are bound to a specific CPU (swapper/n). In
- * RTEMS, the idle threads can move around, so mimic this Linux behaviour.
- */
- snprintf(
- (char *) dst + 4,
- THREAD_NAME_SIZE - 4,
- "/%lu",
- (unsigned long) item->cpu
- );
- }
-}
-
-static void write_sched_switch(
- client_context *ctx,
- per_cpu_context *pcpu,
- const client_item *item
-)
-{
- size_t se_size;
- sched_switch *se;
- uint32_t api_index;
-
- se_size = sizeof( sched_switch ) * BITS_PER_CHAR;
- pcpu->content_size += se_size;
- pcpu->packet_size += se_size;
-
- api_index = get_api_index_of_id( item->data );
- se = &pcpu->sched_switch;
-
- se->header.id = COMPACT_HEADER_ID;
- se->header.event_id = 0;
- se->header.ns = item->ns;
- se->next_tid = is_idle_task_by_api_index( api_index ) ? 0 : item->data;
-
- copy_thread_name( ctx, item, api_index, se->next_comm );
- fwrite( se, sizeof( *se ), 1, pcpu->event_stream );
-}
-
-static void add_thread_name(
- client_context *ctx,
- per_cpu_context *pcpu,
- const client_item *item
-)
-{
- uint64_t name;
- uint32_t api_index;
- uint32_t obj_index;
- size_t i;
-
- if ( pcpu->thread_name_index >= THREAD_NAME_SIZE ) {
- return;
- }
-
- api_index = get_api_index_of_id( pcpu->thread_id );
-
- if ( api_index >= THREAD_API_COUNT ) {
- return;
- }
-
- obj_index = get_obj_index_of_id( pcpu->thread_id );
- name = item->data;
-
- for (
- i = pcpu->thread_name_index;
- i < pcpu->thread_name_index + ctx->base.data_size;
- ++i
- ) {
- ctx->thread_names[ api_index ][ obj_index ][ i ] = (char) name;
- name >>= BITS_PER_CHAR;
- }
-
- pcpu->thread_name_index = i;
-}
-
-static void print_item( client_context *ctx, const client_item *item )
-{
- per_cpu_context *pcpu;
- sched_switch *se;
- uint32_t api_index;
-
- pcpu = &ctx->per_cpu[ item->cpu ];
- se = &pcpu->sched_switch;
-
- if ( pcpu->timestamp_begin == 0 ) {
- pcpu->timestamp_begin = item->ns;
- }
-
- pcpu->timestamp_end = item->ns;
-
- switch ( item->event ) {
- case RTEMS_RECORD_THREAD_SWITCH_OUT:
- api_index = get_api_index_of_id( item->data );
- se->header.ns = item->ns;
-
- if ( is_idle_task_by_api_index( api_index ) ) {
- se->prev_tid = 0;
- se->prev_state = TASK_IDLE;
- } else {
- se->prev_tid = item->data;
- se->prev_state = TASK_RUNNING;
- }
-
- copy_thread_name( ctx, item, api_index, se->prev_comm );
- break;
- case RTEMS_RECORD_THREAD_SWITCH_IN:
- if ( item->ns == se->header.ns ) {
- write_sched_switch( ctx, pcpu, item );
- }
- break;
- case RTEMS_RECORD_THREAD_ID:
- pcpu->thread_id = item->data;
- pcpu->thread_ns = item->ns;
- pcpu->thread_name_index = 0;
- break;
- case RTEMS_RECORD_THREAD_NAME:
- add_thread_name( ctx, pcpu, item );
- break;
- default:
- break;
- }
-}
-
-static rtems_record_client_status handler(
- uint64_t bt,
- uint32_t cpu,
- rtems_record_event event,
- uint64_t data,
- void *arg
-)
-{
- client_item item;
-
- item.ns = rtems_record_client_bintime_to_nanoseconds( bt );
- item.cpu = cpu;
- item.event = event;
- item.data = data;
-
- print_item( arg, &item );
-
- return RTEMS_RECORD_CLIENT_SUCCESS;
-}
-
-static const char metadata[] =
-"/* CTF 1.8 */\n"
-"\n"
-"typealias integer { size = 5; align = 1; signed = false; } := uint5_t;\n"
-"typealias integer { size = 8; align = 8; signed = false; } := uint8_t;\n"
-"typealias integer { size = 32; align = 8; signed = false; } := uint32_t;\n"
-"typealias integer { size = 64; align = 8; signed = false; } := uint64_t;\n"
-"typealias integer { size = 64; align = 8; signed = false; } := unsigned long;\n"
-"\n"
-"trace {\n"
-"\tmajor = 1;\n"
-"\tminor = 8;\n"
-"\tuuid = \"6a7715d0-b502-4c65-8678-6777ac7f755a\";\n"
-"\tbyte_order = le;\n"
-"\tpacket.header := struct {\n"
-"\t\tuint32_t magic;\n"
-"\t\tuint8_t uuid[16];\n"
-"\t\tuint32_t stream_id;\n"
-"\t\tuint64_t stream_instance_id;\n"
-"\t};\n"
-"};\n"
-"\n"
-"env {\n"
-"\thostname = \"Record_Item\";\n"
-"\tdomain = \"kernel\";\n"
-"\tsysname = \"Linux\";\n"
-"\tkernel_release = \"4.18.14-arch1-1-ARCH\";\n"
-"\tkernel_version = \"#1 SMP PREEMPT Sat Thu 17 13:42:37 UTC 2019\";\n"
-"\ttracer_name = \"lttng-modules\";\n"
-"\ttracer_major = 2;\n"
-"\ttracer_minor = 11;\n"
-"\ttracer_patchlevel = 0;\n"
-"};\n"
-"\n"
-"clock {\n"
-"\tname = \"monotonic\";\n"
-"\tuuid = \"234d669d-7651-4bc1-a7fd-af581ecc6232\";\n"
-"\tdescription = \"Monotonic Clock\";\n"
-"\tfreq = 1000000000;\n"
-"\toffset = 1539783991179109789;\n"
-"};\n"
-"\n"
-"typealias integer {\n"
-"\tsize = 27; align = 1; signed = false;\n"
-"\tmap = clock.monotonic.value;\n"
-"} := uint27_clock_monotonic_t;\n"
-"\n"
-"typealias integer {\n"
-"\tsize = 64; align = 8; signed = false;\n"
-"\tmap = clock.monotonic.value;\n"
-"} := uint64_clock_monotonic_t;\n"
-"\n"
-"struct packet_context {\n"
-"\tuint64_clock_monotonic_t timestamp_begin;\n"
-"\tuint64_clock_monotonic_t timestamp_end;\n"
-"\tuint64_t content_size;\n"
-"\tuint64_t packet_size;\n"
-"\tuint64_t packet_seq_num;\n"
-"\tunsigned long events_discarded;\n"
-"\tuint32_t cpu_id;\n"
-"};\n"
-"\n"
-"struct event_header_compact {\n"
-"\tenum : uint5_t { compact = 0 ... 30, extended = 31 } id;\n"
-"\tvariant <id> {\n"
-"\t\tstruct {\n"
-"\t\t\tuint27_clock_monotonic_t timestamp;\n"
-"\t\t} compact;\n"
-"\t\tstruct {\n"
-"\t\t\tuint32_t id;\n"
-"\t\t\tuint64_clock_monotonic_t timestamp;\n"
-"\t\t} extended;\n"
-"\t} v;\n"
-"} align(8);\n"
-"\n"
-"stream {\n"
-"\tid = 0;\n"
-"\tevent.header := struct event_header_compact;\n"
-"\tpacket.context := struct packet_context;\n"
-"};\n"
-"\n"
-"event {\n"
-"\tname = \"sched_switch\";\n"
-"\tid = 0;\n"
-"\tstream_id = 0;\n"
-"\tfields := struct {\n"
-"\t\tinteger { size = 8; align = 8; signed = 0; encoding = UTF8; base = 10;}\
- _prev_comm[16];\n"
-"\t\tinteger { size = 32; align = 8; signed = 1; encoding = none; base = 10; }\
- _prev_tid;\n"
-"\t\tinteger { size = 32; align = 8; signed = 1; encoding = none; base = 10; }\
- _prev_prio;\n"
-"\t\tinteger { size = 64; align = 8; signed = 1; encoding = none; base = 10; }\
- _prev_state;\n"
-"\t\tinteger { size = 8; align = 8; signed = 0; encoding = UTF8; base = 10; }\
- _next_comm[16];\n"
-"\t\tinteger { size = 32; align = 8; signed = 1; encoding = none; base = 10; }\
- _next_tid;\n"
-"\t\tinteger { size = 32; align = 8; signed = 1; encoding = none; base = 10; }\
- _next_prio;\n"
-"\t};\n"
-"};"
-;
-
-static void generate_metadata()
-{
- FILE *file = fopen( "metadata", "w" );
- assert( file != NULL );
- fwrite( metadata, sizeof( metadata ) - 1, 1, file );
- fclose( file );
-}
-
-int main( int argc, char **argv )
-{
- client_context ctx;
- packet_context pkt_ctx;
- size_t pkt_ctx_size;
- const char *host;
- uint16_t port;
- const char *input_file;
- bool input_file_flag;
- bool input_TCP_host;
- bool input_TCP_port;
- int fd;
- int rv;
- int opt;
- int longindex;
- size_t i;
- char filename[ 256 ];
-
- host = "127.0.0.1";
- port = 1234;
- input_file = "raw_data";
- input_file_flag = false;
- input_TCP_host = false;
- input_TCP_port = false;
-
- while (
- ( opt = getopt_long( argc, argv, "hH:p:i:", &longopts[0], &longindex ) )
- != -1
- ) {
- switch ( opt ) {
- case 'h':
- usage( argv );
- exit( EXIT_SUCCESS );
- break;
- case 'H':
- host = optarg;
- input_TCP_host = true;
- break;
- case 'p':
- port = (uint16_t) strtoul( optarg, NULL, 10 );
- input_TCP_port = true;
- break;
- case 'i':
- input_file = optarg;
- assert( input_file != NULL );
- input_file_flag = true;
- break;
- default:
- exit( EXIT_FAILURE );
- break;
- }
- }
-
- if( input_file_flag && ( input_TCP_host || input_TCP_port ) ) {
- printf( "There should be one input medium\n" );
- exit( EXIT_SUCCESS );
- }
-
- memset( &ctx, 0, sizeof( ctx ) );
-
- generate_metadata();
-
- memset( &pkt_ctx, 0, sizeof( pkt_ctx ) );
- memcpy( pkt_ctx.header.uuid, uuid, sizeof( pkt_ctx.header.uuid ) );
- pkt_ctx.header.ctf_magic = CTF_MAGIC;
-
- for ( i = 0; i < RTEMS_RECORD_CLIENT_MAXIMUM_CPU_COUNT; ++i ) {
- FILE *f;
-
- snprintf( filename, sizeof( filename ), "event_%zu", i );
- f = fopen( filename, "wb" );
- assert( f != NULL );
- ctx.per_cpu[ i ].event_stream = f;
- fwrite( &pkt_ctx, sizeof( pkt_ctx ), 1, f );
- }
-
- fd = connect_client( host, port, input_file, input_file_flag );
- rtems_record_client_init( &ctx.base, handler, &ctx );
-
- while ( true ) {
- int buf[ 8192 ];
- ssize_t n;
-
- n = ( input_file_flag ) ? read( fd, buf, sizeof( buf ) ) :
- recv( fd, buf, sizeof( buf ), 0 );
- if ( n > 0 ) {
- rtems_record_client_run( &ctx.base, buf, (size_t) n );
- } else {
- break;
- }
- }
-
- rtems_record_client_destroy( &ctx.base );
- pkt_ctx_size = sizeof( pkt_ctx ) * BITS_PER_CHAR;
-
- for ( i = 0; i < RTEMS_RECORD_CLIENT_MAXIMUM_CPU_COUNT; ++i ) {
- per_cpu_context *pcpu;
-
- pcpu = &ctx.per_cpu[ i ];
- fseek( pcpu->event_stream, 0, SEEK_SET );
-
- pkt_ctx.header.stream_instance_id = i;
- pkt_ctx.timestamp_begin = pcpu->timestamp_begin;
- pkt_ctx.timestamp_end = pcpu->timestamp_end;
- pkt_ctx.content_size = pcpu->content_size + pkt_ctx_size;
- pkt_ctx.packet_size = pcpu->packet_size + pkt_ctx_size;
- pkt_ctx.cpu_id = i;
-
- fwrite( &pkt_ctx, sizeof( pkt_ctx ), 1, pcpu->event_stream );
- fclose( pcpu->event_stream );
- }
-
- rv = close( fd );
- assert( rv == 0 );
-
- return 0;
-}
diff --git a/trace/record/record-main-lttng.cc b/trace/record/record-main-lttng.cc
new file mode 100644
index 0000000..9e10c5e
--- /dev/null
+++ b/trace/record/record-main-lttng.cc
@@ -0,0 +1,547 @@
+/*
+ * SPDX-License-Identifier: BSD-2-Clause
+ *
+ * Copyright (c) 2019 Ravindra Kumar Meena <rmeena840@gmail.com>
+ * Copyright (C) 2018, 2019 embedded brains GmbH
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <rtems/recordclient.h>
+#include <rtems/recorddata.h>
+
+#include <arpa/inet.h>
+#include <assert.h>
+#include <fcntl.h>
+#include <getopt.h>
+#include <inttypes.h>
+#include <netinet/in.h>
+#include <string.h>
+#include <sys/queue.h>
+#include <sys/socket.h>
+#include <unistd.h>
+
+#include <iostream>
+
+#define CTF_MAGIC 0xC1FC1FC1
+#define TASK_RUNNING 0x0000
+#define TASK_IDLE 0x0402
+#define UUID_SIZE 16
+#define THREAD_NAME_SIZE 16
+#define THREAD_API_COUNT 3
+#define THREAD_ID_COUNT 0x10000
+#define BITS_PER_CHAR 8
+#define COMPACT_HEADER_ID 31
+
+static const uint8_t kEmptyThreadName[THREAD_API_COUNT] = "";
+
+static const uint8_t kUUID[] = {0x6a, 0x77, 0x15, 0xd0, 0xb5, 0x02, 0x4c, 0x65,
+ 0x86, 0x78, 0x67, 0x77, 0xac, 0x7f, 0x75, 0x5a};
+
+struct ClientItem {
+ uint64_t ns;
+ uint32_t cpu;
+ rtems_record_event event;
+ uint64_t data;
+};
+
+struct PacketHeader {
+ uint32_t ctf_magic;
+ uint8_t uuid[UUID_SIZE];
+ uint32_t stream_id;
+ uint64_t stream_instance_id;
+} __attribute__((__packed__));
+
+struct PacketContext {
+ PacketHeader header;
+ uint64_t timestamp_begin;
+ uint64_t timestamp_end;
+ uint64_t content_size;
+ uint64_t packet_size;
+ uint64_t packet_seq_num;
+ uint64_t events_discarded;
+ uint32_t cpu_id;
+} __attribute__((__packed__));
+
+struct EventHeaderCompact {
+ uint8_t id;
+ uint32_t event_id;
+ uint64_t ns;
+} __attribute__((__packed__));
+
+struct EventSchedSwitch {
+ EventHeaderCompact header;
+ uint8_t prev_comm[THREAD_NAME_SIZE];
+ int32_t prev_tid;
+ int32_t prev_prio;
+ int64_t prev_state;
+ uint8_t next_comm[THREAD_NAME_SIZE];
+ int32_t next_tid;
+ int32_t next_prio;
+} __attribute__((__packed__));
+
+struct PerCPUContext {
+ FILE* event_stream;
+ uint64_t timestamp_begin;
+ uint64_t timestamp_end;
+ uint64_t content_size;
+ uint64_t packet_size;
+ uint32_t thread_id;
+ uint64_t thread_ns;
+ size_t thread_name_index;
+ EventSchedSwitch sched_switch;
+};
+
+struct LTTNGClient {
+ rtems_record_client_context base;
+ PerCPUContext per_cpu_[RTEMS_RECORD_CLIENT_MAXIMUM_CPU_COUNT];
+
+ /*
+ * @brief Thread names indexed by API and object index.
+ *
+ * The API indices are 0 for Internal API, 1 for Classic API and 2 for
+ * POSIX API.
+ */
+ uint8_t thread_names_[THREAD_API_COUNT][THREAD_ID_COUNT][THREAD_NAME_SIZE];
+};
+
+static int ConnectClient(const char* host,
+ uint16_t port,
+ const char* input_file,
+ bool input_file_flag) {
+ struct sockaddr_in in_addr;
+ int fd;
+ int rv;
+
+ fd = (input_file_flag) ? open(input_file, O_RDONLY)
+ : socket(PF_INET, SOCK_STREAM, 0);
+ assert(fd >= 0);
+
+ memset(&in_addr, 0, sizeof(in_addr));
+ in_addr.sin_family = AF_INET;
+ in_addr.sin_port = htons(port);
+ in_addr.sin_addr.s_addr = inet_addr(host);
+
+ if (!input_file_flag) {
+ rv = connect(fd, (struct sockaddr*)&in_addr, sizeof(in_addr));
+ assert(rv == 0);
+ }
+
+ return fd;
+}
+
+static uint32_t GetAPIIndexOfID(uint32_t id) {
+ return ((id >> 24) & 0x7) - 1;
+}
+
+static uint32_t GetObjIndexOfID(uint32_t id) {
+ return id & (THREAD_ID_COUNT - 1);
+}
+
+static bool IsIdleTaskByAPIIndex(uint32_t api_index) {
+ return api_index == 0;
+}
+
+static void CopyThreadName(const LTTNGClient* ctx,
+ const ClientItem* item,
+ size_t api_index,
+ uint8_t* dst) {
+ const uint8_t* name;
+
+ if (api_index < THREAD_API_COUNT) {
+ name = ctx->thread_names_[api_index][GetObjIndexOfID(item->data)];
+ } else {
+ name = kEmptyThreadName;
+ }
+
+ memcpy(dst, name, THREAD_NAME_SIZE);
+
+ if (IsIdleTaskByAPIIndex(api_index)) {
+ /*
+ * In Linux, the idle threads are bound to a specific CPU (swapper/n). In
+ * RTEMS, the idle threads can move around, so mimic this Linux behaviour.
+ */
+ snprintf(reinterpret_cast<char*>(dst) + 4, THREAD_NAME_SIZE - 4,
+ "/%" PRIu32, item->cpu);
+ }
+}
+
+static void WriteSchedSwitch(LTTNGClient* ctx,
+ PerCPUContext* pcpu,
+ const ClientItem* item) {
+ size_t se_size;
+ EventSchedSwitch* se;
+ uint32_t api_index;
+
+ se_size = sizeof(*se) * BITS_PER_CHAR;
+ pcpu->content_size += se_size;
+ pcpu->packet_size += se_size;
+
+ api_index = GetAPIIndexOfID(item->data);
+ se = &pcpu->sched_switch;
+
+ se->header.id = COMPACT_HEADER_ID;
+ se->header.event_id = 0;
+ se->header.ns = item->ns;
+ se->next_tid = IsIdleTaskByAPIIndex(api_index) ? 0 : item->data;
+
+ CopyThreadName(ctx, item, api_index, se->next_comm);
+ fwrite(se, sizeof(*se), 1, pcpu->event_stream);
+}
+
+static void AddThreadName(LTTNGClient* ctx,
+ PerCPUContext* pcpu,
+ const ClientItem* item) {
+ uint64_t name;
+ uint32_t api_index;
+ uint32_t obj_index;
+ size_t i;
+
+ if (pcpu->thread_name_index >= THREAD_NAME_SIZE) {
+ return;
+ }
+
+ api_index = GetAPIIndexOfID(pcpu->thread_id);
+
+ if (api_index >= THREAD_API_COUNT) {
+ return;
+ }
+
+ obj_index = GetObjIndexOfID(pcpu->thread_id);
+ name = item->data;
+
+ for (i = pcpu->thread_name_index;
+ i < pcpu->thread_name_index + ctx->base.data_size; ++i) {
+ ctx->thread_names_[api_index][obj_index][i] = static_cast<uint8_t>(name);
+ name >>= BITS_PER_CHAR;
+ }
+
+ pcpu->thread_name_index = i;
+}
+
+static void PrintItem(LTTNGClient* ctx, const ClientItem* item) {
+ PerCPUContext* pcpu;
+ EventSchedSwitch* se;
+ uint32_t api_index;
+
+ pcpu = &ctx->per_cpu_[item->cpu];
+ se = &pcpu->sched_switch;
+
+ if (pcpu->timestamp_begin == 0) {
+ pcpu->timestamp_begin = item->ns;
+ }
+
+ pcpu->timestamp_end = item->ns;
+
+ switch (item->event) {
+ case RTEMS_RECORD_THREAD_SWITCH_OUT:
+ api_index = GetAPIIndexOfID(item->data);
+ se->header.ns = item->ns;
+
+ if (IsIdleTaskByAPIIndex(api_index)) {
+ se->prev_tid = 0;
+ se->prev_state = TASK_IDLE;
+ } else {
+ se->prev_tid = item->data;
+ se->prev_state = TASK_RUNNING;
+ }
+
+ CopyThreadName(ctx, item, api_index, se->prev_comm);
+ break;
+ case RTEMS_RECORD_THREAD_SWITCH_IN:
+ if (item->ns == se->header.ns) {
+ WriteSchedSwitch(ctx, pcpu, item);
+ }
+ break;
+ case RTEMS_RECORD_THREAD_ID:
+ pcpu->thread_id = item->data;
+ pcpu->thread_ns = item->ns;
+ pcpu->thread_name_index = 0;
+ break;
+ case RTEMS_RECORD_THREAD_NAME:
+ AddThreadName(ctx, pcpu, item);
+ break;
+ default:
+ break;
+ }
+}
+
+static rtems_record_client_status Handler(uint64_t bt,
+ uint32_t cpu,
+ rtems_record_event event,
+ uint64_t data,
+ void* arg) {
+ ClientItem item;
+
+ item.ns = rtems_record_client_bintime_to_nanoseconds(bt);
+ item.cpu = cpu;
+ item.event = event;
+ item.data = data;
+
+ PrintItem(static_cast<LTTNGClient*>(arg), &item);
+
+ return RTEMS_RECORD_CLIENT_SUCCESS;
+}
+
+static const char kMetadata[] =
+ "/* CTF 1.8 */\n"
+ "\n"
+ "typealias integer { size = 5; align = 1; signed = false; } := uint5_t;\n"
+ "typealias integer { size = 8; align = 8; signed = false; } := uint8_t;\n"
+ "typealias integer { size = 32; align = 8; signed = true; } := int32_t;\n"
+ "typealias integer { size = 32; align = 8; signed = false; } := uint32_t;\n"
+ "typealias integer { size = 64; align = 8; signed = true; } := int64_t;\n"
+ "typealias integer { size = 64; align = 8; signed = false; } := uint64_t;\n"
+ "\n"
+ "typealias integer {\n"
+ "\tsize = 8; align = 8; signed = 0; encoding = UTF8; base = 10;\n"
+ "} := utf8_t;\n"
+ "\n"
+ "typealias integer {\n"
+ "\tsize = 27; align = 1; signed = false;\n"
+ "\tmap = clock.monotonic.value;\n"
+ "} := uint27_clock_monotonic_t;\n"
+ "\n"
+ "typealias integer {\n"
+ "\tsize = 64; align = 8; signed = false;\n"
+ "\tmap = clock.monotonic.value;\n"
+ "} := uint64_clock_monotonic_t;\n"
+ "\n"
+ "\n"
+ "trace {\n"
+ "\tmajor = 1;\n"
+ "\tminor = 8;\n"
+ "\tuuid = \"6a7715d0-b502-4c65-8678-6777ac7f755a\";\n"
+ "\tbyte_order = le;\n"
+ "\tpacket.header := struct {\n"
+ "\t\tuint32_t magic;\n"
+ "\t\tuint8_t uuid[16];\n"
+ "\t\tuint32_t stream_id;\n"
+ "\t\tuint64_t stream_instance_id;\n"
+ "\t};\n"
+ "};\n"
+ "\n"
+ "env {\n"
+ "\thostname = \"Record_Item\";\n"
+ "\tdomain = \"kernel\";\n"
+ "\tsysname = \"Linux\";\n"
+ "\tkernel_release = \"4.18.14-arch1-1-ARCH\";\n"
+ "\tkernel_version = \"#1 SMP PREEMPT Sat Thu 17 13:42:37 UTC 2019\";\n"
+ "\ttracer_name = \"lttng-modules\";\n"
+ "\ttracer_major = 2;\n"
+ "\ttracer_minor = 11;\n"
+ "\ttracer_patchlevel = 0;\n"
+ "};\n"
+ "\n"
+ "clock {\n"
+ "\tname = \"monotonic\";\n"
+ "\tuuid = \"234d669d-7651-4bc1-a7fd-af581ecc6232\";\n"
+ "\tdescription = \"Monotonic Clock\";\n"
+ "\tfreq = 1000000000;\n"
+ "\toffset = 1539783991179109789;\n"
+ "};\n"
+ "\n"
+ "struct packet_context {\n"
+ "\tuint64_clock_monotonic_t timestamp_begin;\n"
+ "\tuint64_clock_monotonic_t timestamp_end;\n"
+ "\tuint64_t content_size;\n"
+ "\tuint64_t packet_size;\n"
+ "\tuint64_t packet_seq_num;\n"
+ "\tuint64_t events_discarded;\n"
+ "\tuint32_t cpu_id;\n"
+ "};\n"
+ "\n"
+ "struct event_header_compact {\n"
+ "\tenum : uint5_t { compact = 0 ... 30, extended = 31 } id;\n"
+ "\tvariant <id> {\n"
+ "\t\tstruct {\n"
+ "\t\t\tuint27_clock_monotonic_t timestamp;\n"
+ "\t\t} compact;\n"
+ "\t\tstruct {\n"
+ "\t\t\tuint32_t id;\n"
+ "\t\t\tuint64_clock_monotonic_t timestamp;\n"
+ "\t\t} extended;\n"
+ "\t} v;\n"
+ "} align(8);\n"
+ "\n"
+ "stream {\n"
+ "\tid = 0;\n"
+ "\tevent.header := struct event_header_compact;\n"
+ "\tpacket.context := struct packet_context;\n"
+ "};\n"
+ "\n"
+ "event {\n"
+ "\tname = \"sched_switch\";\n"
+ "\tid = 0;\n"
+ "\tstream_id = 0;\n"
+ "\tfields := struct {\n"
+ "\t\tutf8_t _prev_comm[16];\n"
+ "\t\tint32_t _prev_tid;\n"
+ "\t\tint32_t _prev_prio;\n"
+ "\t\tint64_t _prev_state;\n"
+ "\t\tutf8_t _next_comm[16];\n"
+ "\t\tint32_t _next_tid;\n"
+ "\t\tint32_t _next_prio;\n"
+ "\t};\n"
+ "};\n";
+
+static void GenerateMetadata() {
+ FILE* file = fopen("metadata", "w");
+ assert(file != NULL);
+ fwrite(kMetadata, sizeof(kMetadata) - 1, 1, file);
+ fclose(file);
+}
+
+static const struct option kLongOpts[] = {{"help", 0, NULL, 'h'},
+ {"host", 1, NULL, 'H'},
+ {"port", 1, NULL, 'p'},
+ {"input", 1, NULL, 'i'},
+ {NULL, 0, NULL, 0}};
+
+static void Usage(char** argv) {
+ std::cout << argv[0] << "%s [--host=HOST] [--port=PORT] [--input=INPUT]"
+ << std::endl
+ << std::endl
+ << "Mandatory arguments to long options are mandatory for short "
+ "options too."
+ << std::endl
+ << " -h, --help print this help text" << std::endl
+ << " -H, --host=HOST the host IPv4 address of the "
+ "record server"
+ << std::endl
+ << " -p, --port=PORT the TCP port of the record server"
+ << std::endl
+ << " -i, --input=INPUT the input file" << std::endl;
+}
+
+int main(int argc, char** argv) {
+ LTTNGClient ctx;
+ PacketContext pkt_ctx;
+ size_t pkt_ctx_size;
+ const char* host;
+ uint16_t port;
+ const char* input_file;
+ bool input_file_flag;
+ bool input_TCP_host;
+ bool input_TCP_port;
+ int fd;
+ int rv;
+ int opt;
+ int longindex;
+ size_t i;
+ char filename[256];
+
+ host = "127.0.0.1";
+ port = 1234;
+ input_file = "raw_data";
+ input_file_flag = false;
+ input_TCP_host = false;
+ input_TCP_port = false;
+
+ while ((opt = getopt_long(argc, argv, "hH:p:i:", &kLongOpts[0],
+ &longindex)) != -1) {
+ switch (opt) {
+ case 'h':
+ Usage(argv);
+ return 0;
+ case 'H':
+ host = optarg;
+ input_TCP_host = true;
+ break;
+ case 'p':
+ port = (uint16_t)strtoul(optarg, NULL, 10);
+ input_TCP_port = true;
+ break;
+ case 'i':
+ input_file = optarg;
+ assert(input_file != NULL);
+ input_file_flag = true;
+ break;
+ default:
+ return 1;
+ }
+ }
+
+ if (input_file_flag && (input_TCP_host || input_TCP_port)) {
+ printf("There should be one input medium\n");
+ exit(EXIT_SUCCESS);
+ }
+
+ memset(&ctx, 0, sizeof(ctx));
+
+ GenerateMetadata();
+
+ memset(&pkt_ctx, 0, sizeof(pkt_ctx));
+ memcpy(pkt_ctx.header.uuid, kUUID, sizeof(pkt_ctx.header.uuid));
+ pkt_ctx.header.ctf_magic = CTF_MAGIC;
+
+ for (i = 0; i < RTEMS_RECORD_CLIENT_MAXIMUM_CPU_COUNT; ++i) {
+ FILE* f;
+
+ snprintf(filename, sizeof(filename), "event_%zu", i);
+ f = fopen(filename, "wb");
+ assert(f != NULL);
+ ctx.per_cpu_[i].event_stream = f;
+ fwrite(&pkt_ctx, sizeof(pkt_ctx), 1, f);
+ }
+
+ fd = ConnectClient(host, port, input_file, input_file_flag);
+ rtems_record_client_init(&ctx.base, Handler, &ctx);
+
+ while (true) {
+ int buf[8192];
+ ssize_t n;
+
+ n = (input_file_flag) ? read(fd, buf, sizeof(buf))
+ : recv(fd, buf, sizeof(buf), 0);
+ if (n > 0) {
+ rtems_record_client_run(&ctx.base, buf, (size_t)n);
+ } else {
+ break;
+ }
+ }
+
+ rtems_record_client_destroy(&ctx.base);
+ pkt_ctx_size = sizeof(pkt_ctx) * BITS_PER_CHAR;
+
+ for (i = 0; i < RTEMS_RECORD_CLIENT_MAXIMUM_CPU_COUNT; ++i) {
+ PerCPUContext* pcpu;
+
+ pcpu = &ctx.per_cpu_[i];
+ fseek(pcpu->event_stream, 0, SEEK_SET);
+
+ pkt_ctx.header.stream_instance_id = i;
+ pkt_ctx.timestamp_begin = pcpu->timestamp_begin;
+ pkt_ctx.timestamp_end = pcpu->timestamp_end;
+ pkt_ctx.content_size = pcpu->content_size + pkt_ctx_size;
+ pkt_ctx.packet_size = pcpu->packet_size + pkt_ctx_size;
+ pkt_ctx.cpu_id = i;
+
+ fwrite(&pkt_ctx, sizeof(pkt_ctx), 1, pcpu->event_stream);
+ fclose(pcpu->event_stream);
+ }
+
+ rv = close(fd);
+ assert(rv == 0);
+
+ return 0;
+}
diff --git a/trace/wscript b/trace/wscript
index a0f5498..bc28e85 100644
--- a/trace/wscript
+++ b/trace/wscript
@@ -29,9 +29,11 @@ def init(ctx):
def options(opt):
opt.load('compiler_c')
+ opt.load('compiler_cxx')
def configure(conf):
conf.load('compiler_c')
+ conf.load('compiler_cxx')
def build(bld):
#
@@ -57,7 +59,7 @@ def build(bld):
# Build rtems-record-lttng
#
bld.program(target = 'rtems-record-lttng',
- source = ['record/record-client.c', 'record/record-main-lttng.c'],
+ source = ['record/record-client.c', 'record/record-main-lttng.cc'],
includes = ['record'],
defines = defines,
cflags = conf['cflags'] + conf['warningflags'],