Hello, attached are two patches which convert the rtems-record-lttng client program from C to C++. I used
clang-format -style=Chromium -i trace/record/record-main-lttng.cc to format the source. -- Sebastian Huber, embedded brains GmbH Address : Dornierstr. 4, D-82178 Puchheim, Germany Phone : +49 89 189 47 41-16 Fax : +49 89 189 47 41-09 E-Mail : sebastian.hu...@embedded-brains.de PGP : Public key available on request. Diese Nachricht ist keine geschäftliche Mitteilung im Sinne des EHUG.
From 1318f60f47c3a52e8b1b52d9834a8604f31444e9 Mon Sep 17 00:00:00 2001 From: Sebastian Huber <sebastian.hu...@embedded-brains.de> Date: Thu, 29 Aug 2019 07:53:35 +0200 Subject: [PATCH 1/2] 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 | 549 +++++++++++++++++++++++++++++++++++ trace/wscript | 4 +- 3 files changed, 552 insertions(+), 586 deletions(-) delete mode 100644 trace/record/record-main-lttng.c create mode 100644 trace/record/record-main-lttng.cc 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 <rmeena...@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..f856b9c --- /dev/null +++ b/trace/record/record-main-lttng.cc @@ -0,0 +1,549 @@ +/* + * SPDX-License-Identifier: BSD-2-Clause + * + * Copyright (c) 2019 Ravindra Kumar Meena <rmeena...@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 <sys/queue.h> +#include <sys/socket.h> + +#include <assert.h> +#include <fcntl.h> +#include <getopt.h> +#include <inttypes.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> + +#include <arpa/inet.h> +#include <netinet/in.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 kLongOpts[] = {{"help", 0, NULL, 'h'}, + {"host", 1, NULL, 'H'}, + {"port", 1, NULL, 'p'}, + {"input", 1, NULL, 'i'}, + {NULL, 0, NULL, 0}}; + +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 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}; + +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 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); +} + +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); + 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)); + + 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'], -- 2.16.4
From 8560cfa3d6509578edf12da7f546db8d4605b8a6 Mon Sep 17 00:00:00 2001 From: Sebastian Huber <sebastian.hu...@embedded-brains.de> Date: Fri, 30 Aug 2019 06:30:28 +0200 Subject: [PATCH 2/2] record: Add Client base class Update #3665. --- trace/record/client.h | 120 +++++++++++++ trace/record/record-main-lttng.cc | 358 +++++++++++++++++--------------------- 2 files changed, 276 insertions(+), 202 deletions(-) create mode 100644 trace/record/client.h diff --git a/trace/record/client.h b/trace/record/client.h new file mode 100644 index 0000000..578d91d --- /dev/null +++ b/trace/record/client.h @@ -0,0 +1,120 @@ +/* + * SPDX-License-Identifier: BSD-2-Clause + * + * 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 <assert.h> +#include <fcntl.h> +#include <sys/socket.h> +#include <sys/stat.h> +#include <unistd.h> + +#include <arpa/inet.h> +#include <netinet/in.h> + +#include <csignal> +#include <cstring> + +#ifndef RTEMS_TOOLS_TRACE_RECORD_CLIENT_H_ +#define RTEMS_TOOLS_TRACE_RECORD_CLIENT_H_ + +class Client { + public: + Client() { + // Nothing to do + } + + void Open(const char* file) { + assert(fd_ == -1); + fd_ = open(file, O_RDONLY); + assert(fd_ >= 0); + reader_ = ReadFile; + } + + void Connect(const char* host, uint16_t port) { + assert(fd_ == -1); + fd_ = socket(PF_INET, SOCK_STREAM, 0); + assert(fd_ >= 0); + + struct sockaddr_in in_addr; + 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); + + int rv = connect(fd_, (struct sockaddr*)&in_addr, sizeof(in_addr)); + assert(rv == 0); + + reader_ = ReadSocket; + } + + void Run() { + while (true) { + int buf[8192]; + ssize_t n = (*reader_)(fd_, buf, sizeof(buf)); + + if (n > 0) { + rtems_record_client_run(&base_, buf, static_cast<size_t>(n)); + } else { + break; + } + } + } + + void RequestStop() { stop_ = 1; } + + void Destroy() { + int rv = close(fd_); + assert(rv == 0); + + rtems_record_client_destroy(&base_); + } + + protected: + void Initialize(rtems_record_client_handler handler) { + rtems_record_client_init(&base_, handler, this); + } + + size_t data_size() const { return base_.data_size; }; + + private: + rtems_record_client_context base_; + int fd_ = -1; + ssize_t (*reader_)(int fd, void* buf, size_t n) = nullptr; + sig_atomic_t stop_ = 0; + + static ssize_t ReadFile(int fd, void* buf, size_t n) { + return ::read(fd, buf, n); + } + + static ssize_t ReadSocket(int fd, void* buf, size_t n) { + return ::recv(fd, buf, n, 0); + } +}; + +#endif // RTEMS_TOOLS_TRACE_RECORD_CLIENT_H_ diff --git a/trace/record/record-main-lttng.cc b/trace/record/record-main-lttng.cc index f856b9c..bba03d0 100644 --- a/trace/record/record-main-lttng.cc +++ b/trace/record/record-main-lttng.cc @@ -26,23 +26,12 @@ * POSSIBILITY OF SUCH DAMAGE. */ -#include <rtems/recordclient.h> -#include <rtems/recorddata.h> +#include "client.h" -#include <sys/queue.h> -#include <sys/socket.h> - -#include <assert.h> -#include <fcntl.h> #include <getopt.h> #include <inttypes.h> #include <stdio.h> #include <stdlib.h> -#include <string.h> -#include <unistd.h> - -#include <arpa/inet.h> -#include <netinet/in.h> #define CTF_MAGIC 0xC1FC1FC1 #define TASK_RUNNING 0x0000 @@ -54,11 +43,10 @@ #define BITS_PER_CHAR 8 #define COMPACT_HEADER_ID 31 -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 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; @@ -85,6 +73,8 @@ struct PacketContext { uint32_t cpu_id; } __attribute__((__packed__)); +static const size_t kPacketContextBits = sizeof(PacketContext) * BITS_PER_CHAR; + struct EventHeaderCompact { uint8_t id; uint32_t event_id; @@ -102,6 +92,9 @@ struct EventSchedSwitch { int32_t next_prio; } __attribute__((__packed__)); +static const size_t kEventSchedSwitchBits = + sizeof(EventSchedSwitch) * BITS_PER_CHAR; + struct PerCPUContext { FILE* event_stream; uint64_t timestamp_begin; @@ -114,8 +107,21 @@ struct PerCPUContext { EventSchedSwitch sched_switch; }; -struct LTTNGClient { - rtems_record_client_context base; +class LTTNGClient : public Client { + public: + LTTNGClient() { + Initialize(LTTNGClient::HandlerCaller); + + 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; + } + + void OpenStreamFiles(); + + void CloseStreamFiles(); + + private: PerCPUContext per_cpu_[RTEMS_RECORD_CLIENT_MAXIMUM_CPU_COUNT]; /* @@ -125,12 +131,33 @@ struct LTTNGClient { * POSIX API. */ uint8_t thread_names_[THREAD_API_COUNT][THREAD_ID_COUNT][THREAD_NAME_SIZE]; -}; -static const uint8_t kEmptyThreadName[THREAD_API_COUNT] = ""; + PacketContext pkt_ctx_; -static const uint8_t kUUID[] = {0x6a, 0x77, 0x15, 0xd0, 0xb5, 0x02, 0x4c, 0x65, - 0x86, 0x78, 0x67, 0x77, 0xac, 0x7f, 0x75, 0x5a}; + static rtems_record_client_status HandlerCaller(uint64_t bt, + uint32_t cpu, + rtems_record_event event, + uint64_t data, + void* arg) { + LTTNGClient& self = *static_cast<LTTNGClient*>(arg); + return self.Handler(bt, cpu, event, data); + } + + rtems_record_client_status Handler(uint64_t bt, + uint32_t cpu, + rtems_record_event event, + uint64_t data); + + void CopyThreadName(const ClientItem& item, + size_t api_index, + uint8_t* dst) const; + + void WriteSchedSwitch(PerCPUContext* pcpu, const ClientItem& item); + + void AddThreadName(PerCPUContext* pcpu, const ClientItem& item); + + void PrintItem(const ClientItem& item); +}; static void usage(char** argv) { printf( @@ -146,31 +173,6 @@ static void usage(char** argv) { argv[0]); } -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; } @@ -183,14 +185,13 @@ 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) { +void LTTNGClient::CopyThreadName(const ClientItem& item, + size_t api_index, + uint8_t* dst) const { const uint8_t* name; if (api_index < THREAD_API_COUNT) { - name = ctx->thread_names_[api_index][GetObjIndexOfID(item->data)]; + name = thread_names_[api_index][GetObjIndexOfID(item.data)]; } else { name = kEmptyThreadName; } @@ -203,115 +204,96 @@ static void CopyThreadName(const LTTNGClient* ctx, * 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); + "/%" PRIu32, item.cpu); } } -static void WriteSchedSwitch(LTTNGClient* ctx, - PerCPUContext* pcpu, - const ClientItem* item) { - size_t se_size; - EventSchedSwitch* se; - uint32_t api_index; +void LTTNGClient::WriteSchedSwitch(PerCPUContext* pcpu, + const ClientItem& item) { + pcpu->content_size += kEventSchedSwitchBits; + pcpu->packet_size += kEventSchedSwitchBits; - se_size = sizeof(*se) * BITS_PER_CHAR; - pcpu->content_size += se_size; - pcpu->packet_size += se_size; + EventSchedSwitch& ss = pcpu->sched_switch; + ss.header.id = COMPACT_HEADER_ID; + ss.header.event_id = 0; + ss.header.ns = item.ns; - api_index = GetAPIIndexOfID(item->data); - se = &pcpu->sched_switch; + uint32_t api_index = GetAPIIndexOfID(item.data); + ss.next_tid = IsIdleTaskByAPIIndex(api_index) ? 0 : item.data; - 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); + CopyThreadName(item, api_index, ss.next_comm); + fwrite(&ss, sizeof(ss), 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; - +void LTTNGClient::AddThreadName(PerCPUContext* pcpu, const ClientItem& item) { if (pcpu->thread_name_index >= THREAD_NAME_SIZE) { return; } - api_index = GetAPIIndexOfID(pcpu->thread_id); - + uint32_t 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); + uint32_t obj_index = GetObjIndexOfID(pcpu->thread_id); + uint64_t name = item.data; + size_t i; + for (i = pcpu->thread_name_index; i < pcpu->thread_name_index + data_size(); + ++i) { + 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; +void LTTNGClient::PrintItem(const ClientItem& item) { + PerCPUContext& pcpu = per_cpu_[item.cpu]; + if (pcpu.timestamp_begin == 0) { + pcpu.timestamp_begin = item.ns; } - pcpu->timestamp_end = 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; + EventSchedSwitch& ss = pcpu.sched_switch; + switch (item.event) { + case RTEMS_RECORD_THREAD_SWITCH_OUT: { + uint32_t api_index = GetAPIIndexOfID(item.data); + ss.header.ns = item.ns; if (IsIdleTaskByAPIIndex(api_index)) { - se->prev_tid = 0; - se->prev_state = TASK_IDLE; + ss.prev_tid = 0; + ss.prev_state = TASK_IDLE; } else { - se->prev_tid = item->data; - se->prev_state = TASK_RUNNING; + ss.prev_tid = item.data; + ss.prev_state = TASK_RUNNING; } - CopyThreadName(ctx, item, api_index, se->prev_comm); + CopyThreadName(item, api_index, ss.prev_comm); break; + } case RTEMS_RECORD_THREAD_SWITCH_IN: - if (item->ns == se->header.ns) { - WriteSchedSwitch(ctx, pcpu, item); + if (item.ns == ss.header.ns) { + WriteSchedSwitch(&pcpu, item); } break; case RTEMS_RECORD_THREAD_ID: - pcpu->thread_id = item->data; - pcpu->thread_ns = item->ns; - pcpu->thread_name_index = 0; + 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); + AddThreadName(&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) { +rtems_record_client_status LTTNGClient::Handler(uint64_t bt, + uint32_t cpu, + rtems_record_event event, + uint64_t data) { ClientItem item; item.ns = rtems_record_client_bintime_to_nanoseconds(bt); @@ -319,11 +301,39 @@ static rtems_record_client_status Handler(uint64_t bt, item.event = event; item.data = data; - PrintItem(static_cast<LTTNGClient*>(arg), &item); + PrintItem(item); return RTEMS_RECORD_CLIENT_SUCCESS; } +void LTTNGClient::OpenStreamFiles() { + for (size_t i = 0; i < RTEMS_RECORD_CLIENT_MAXIMUM_CPU_COUNT; ++i) { + char filename[256]; + snprintf(filename, sizeof(filename), "event_%zu", i); + FILE* f = fopen(filename, "wb"); + assert(f != NULL); + per_cpu_[i].event_stream = f; + fwrite(&pkt_ctx_, sizeof(pkt_ctx_), 1, f); + } +} + +void LTTNGClient::CloseStreamFiles() { + for (size_t i = 0; i < RTEMS_RECORD_CLIENT_MAXIMUM_CPU_COUNT; ++i) { + PerCPUContext* pcpu = &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 + kPacketContextBits; + pkt_ctx_.packet_size = pcpu->packet_size + kPacketContextBits; + pkt_ctx_.cpu_id = i; + + fwrite(&pkt_ctx_, sizeof(pkt_ctx_), 1, pcpu->event_stream); + fclose(pcpu->event_stream); + } +} + static const char kMetadata[] = "/* CTF 1.8 */\n" "\n" @@ -433,29 +443,25 @@ static void GenerateMetadata() { fclose(file); } +static LTTNGClient client; + +static void SignalHandler(int s) { + client.RequestStop(); + signal(s, SIG_DFL); +} + +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}}; + 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; + const char* host = "127.0.0.1"; + uint16_t port = 1234; + const char* file = nullptr; 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) { @@ -466,16 +472,12 @@ int main(int argc, char** argv) { 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; + file = optarg; break; default: exit(EXIT_FAILURE); @@ -483,67 +485,19 @@ int main(int argc, char** argv) { } } - 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(); + client.OpenStreamFiles(); - 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); + if (file != nullptr) { + client.Open(file); + } else { + client.Connect(host, port); } - rv = close(fd); - assert(rv == 0); + signal(SIGINT, SignalHandler); + client.Run(); + client.Destroy(); + client.CloseStreamFiles(); return 0; } -- 2.16.4
_______________________________________________ devel mailing list devel@rtems.org http://lists.rtems.org/mailman/listinfo/devel