[rtems-tools commit] record: Convert to C++

Sebastian Huber sebh at rtems.org
Tue Sep 3 13:03:18 UTC 2019


Module:    rtems-tools
Branch:    master
Commit:    e0ac299e06c8ecd50c1c0de62a397ae0bb44bf22
Changeset: http://git.rtems.org/rtems-tools/commit/?id=e0ac299e06c8ecd50c1c0de62a397ae0bb44bf22

Author:    Sebastian Huber <sebastian.huber at embedded-brains.de>
Date:      Thu Aug 29 07:53:35 2019 +0200

record: Convert to C++

Formatted with:

clang-format -style=Chromium -i trace/record/record-main-lttng.cc

Update #3665.

---

 trace/record/record-main-lttng.c  | 585 --------------------------------------
 trace/record/record-main-lttng.cc | 547 +++++++++++++++++++++++++++++++++++
 trace/wscript                     |   4 +-
 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 at 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 at 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'],




More information about the vc mailing list