From patchwork Wed Aug 28 08:57:38 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: "Tzvetomir Stoyanov (VMware)" X-Patchwork-Id: 11118303 Return-Path: Received: from mail.kernel.org (pdx-korg-mail-1.web.codeaurora.org [172.30.200.123]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id 3A79D18B7 for ; Wed, 28 Aug 2019 08:57:52 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.kernel.org (Postfix) with ESMTP id 1A8182339E for ; Wed, 28 Aug 2019 08:57:52 +0000 (UTC) Authentication-Results: mail.kernel.org; dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b="iWw8HQ7e" Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1726408AbfH1I5v (ORCPT ); Wed, 28 Aug 2019 04:57:51 -0400 Received: from mail-wr1-f68.google.com ([209.85.221.68]:37561 "EHLO mail-wr1-f68.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1726293AbfH1I5v (ORCPT ); Wed, 28 Aug 2019 04:57:51 -0400 Received: by mail-wr1-f68.google.com with SMTP id z11so1647315wrt.4 for ; Wed, 28 Aug 2019 01:57:50 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20161025; h=from:to:cc:subject:date:message-id:in-reply-to:references :mime-version:content-transfer-encoding; bh=eai9MBbxCuXWSarZzFNMEJ1uUK6ncd5rWyIboivmjk0=; b=iWw8HQ7etg5GU6Om7CuKRAinaiEWHEuHkmQGhTURTLS0eXPR8/Ehkhgveh/PL8HpME J4y6yI35MYLRMz6HbeCMALVCeIOqWfBEIkiVm7pyedYDDVXtkd5ERE/yyChEv2yPWmia s94lQ31X5pffrf5Y7MTN902MUaMu18wME0v5QvLYTF5JedtNwRkadcmq17cUBcpjTadF c/sZo9vCrvX+VJE0tqmepke0GMvu4Nw5s7hiLPO6+gblhhUnNJm9ZZgLQsczNoNXzdDJ 6e73bLr90Eg3nDYN+k1tDkQ7+r6Yk5PRrXDy/ZrxX/MqcHiP4AYG8cSr95XxuzNBTauw ViOg== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references:mime-version:content-transfer-encoding; bh=eai9MBbxCuXWSarZzFNMEJ1uUK6ncd5rWyIboivmjk0=; b=MFkkKO1wNXHO4f37vlDNYHYnZ5aD7AvWH4cYYL9N/nnc/bWTBoB0pJ00i7nnrralaO ro+gpEQIbGBAsMRpl4H3tS0bd6fvoyWlFw79N4IoujeUgki3aJf6+CcUPJovCFDfe7Qw tEZL7Nbfx3+Mxl7Ia2UFAkJTyj3emYV1Myj8nIKDISJeHbL8IzvFrA10oaDDIVEDv4NL I2dRYdW78WNxBkntcR0iL1i1As17AHcfd67hPzxXGrQqbqVyXS7qJT0JsG+m+Y5xd8dB CcdeN4Pa7vEljKs9VkdqW56/eYQL1Xg+o8iMyW+9g5fp2i0akxoHtT7LsUiOu+HYwww2 NFLQ== X-Gm-Message-State: APjAAAX2O/RMvG9S+2Y9rCN1+EOvTc8SYLD9O6byQIaT3zMuefrShifA ivx3taRoihxaHpvgjwtoYrLrWeDU X-Google-Smtp-Source: APXvYqxjZKL0tMiKmTSFmL+NruTybWB124o6vqe3dRuocVtJ4CzbBj0l6WX/QfpSN4WxcE43PHp0sg== X-Received: by 2002:adf:a48f:: with SMTP id g15mr3364386wrb.172.1566982669533; Wed, 28 Aug 2019 01:57:49 -0700 (PDT) Received: from oberon.eng.vmware.com ([146.247.46.5]) by smtp.gmail.com with ESMTPSA id u186sm2579433wmu.26.2019.08.28.01.57.48 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Wed, 28 Aug 2019 01:57:48 -0700 (PDT) From: "Tzvetomir Stoyanov (VMware)" To: rostedt@goodmis.org Cc: linux-trace-devel@vger.kernel.org Subject: [PATCH v12 1/9] trace-cmd: Implemented new lib API: tracecmd_local_events_system() Date: Wed, 28 Aug 2019 11:57:38 +0300 Message-Id: <20190828085746.26231-2-tz.stoyanov@gmail.com> X-Mailer: git-send-email 2.21.0 In-Reply-To: <20190828085746.26231-1-tz.stoyanov@gmail.com> References: <20190828085746.26231-1-tz.stoyanov@gmail.com> MIME-Version: 1.0 Sender: linux-trace-devel-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-trace-devel@vger.kernel.org From: Tzvetomir Stoyanov The new tracecmd lib API tracecmd_local_events_system() creates a tep handler and initializes it with the events of the specified subsystems. Signed-off-by: Tzvetomir Stoyanov --- include/trace-cmd/trace-cmd.h | 2 + lib/trace-cmd/trace-util.c | 98 ++++++++++++++++++++++++----------- 2 files changed, 69 insertions(+), 31 deletions(-) diff --git a/include/trace-cmd/trace-cmd.h b/include/trace-cmd/trace-cmd.h index 9a984c1..da29d53 100644 --- a/include/trace-cmd/trace-cmd.h +++ b/include/trace-cmd/trace-cmd.h @@ -32,6 +32,8 @@ void tracecmd_unload_plugins(struct tep_plugin_list *list, struct tep_handle *pe char **tracecmd_event_systems(const char *tracing_dir); char **tracecmd_system_events(const char *tracing_dir, const char *system); struct tep_handle *tracecmd_local_events(const char *tracing_dir); +struct tep_handle *tracecmd_local_events_system(const char *tracing_dir, + const char * const *sys_names); int tracecmd_fill_local_events(const char *tracing_dir, struct tep_handle *pevent, int *parsing_failures); char **tracecmd_local_plugins(const char *tracing_dir); diff --git a/lib/trace-cmd/trace-util.c b/lib/trace-cmd/trace-util.c index d3bb333..9ccf3b3 100644 --- a/lib/trace-cmd/trace-util.c +++ b/lib/trace-cmd/trace-util.c @@ -1120,39 +1120,20 @@ static int read_header(struct tep_handle *pevent, const char *events_dir) return ret; } -/** - * tracecmd_local_events - create a pevent from the events on system - * @tracing_dir: The directory that contains the events. - * - * Returns a pevent structure that contains the pevents local to - * the system. - */ -struct tep_handle *tracecmd_local_events(const char *tracing_dir) +static bool contains(const char *name, const char * const *names) { - struct tep_handle *pevent = NULL; - - pevent = tep_alloc(); - if (!pevent) - return NULL; - - if (tracecmd_fill_local_events(tracing_dir, pevent, NULL)) { - tep_free(pevent); - pevent = NULL; - } - - return pevent; + if (!names) + return false; + for (; *names; names++) + if (strcmp(name, *names) == 0) + return true; + return false; } -/** - * tracecmd_fill_local_events - Fill a pevent with the events on system - * @tracing_dir: The directory that contains the events. - * @pevent: Allocated pevent which will be filled - * @parsing_failures: return number of failures while parsing the event files - * - * Returns whether the operation succeeded - */ -int tracecmd_fill_local_events(const char *tracing_dir, - struct tep_handle *pevent, int *parsing_failures) +static int tracecmd_fill_local_events_system(const char *tracing_dir, + struct tep_handle *pevent, + const char * const *sys_names, + int *parsing_failures) { struct dirent *dent; char *events_dir; @@ -1194,7 +1175,8 @@ int tracecmd_fill_local_events(const char *tracing_dir, if (strcmp(name, ".") == 0 || strcmp(name, "..") == 0) continue; - + if (!contains(name, sys_names)) + continue; sys = append_file(events_dir, name); ret = stat(sys, &st); if (ret < 0 || !S_ISDIR(st.st_mode)) { @@ -1220,6 +1202,60 @@ int tracecmd_fill_local_events(const char *tracing_dir, return ret; } +/** + * tracecmd_local_events_system - create a tep from the events of the specified subsystem. + * + * @tracing_dir: The directory that contains the events. + * @sys_name: Array of system names, to load the events from. + * The last element from the array must be NULL + * + * Returns a tep structure that contains the tep local to + * the system. + */ +struct tep_handle *tracecmd_local_events_system(const char *tracing_dir, + const char * const *sys_names) +{ + struct tep_handle *tep = NULL; + + tep = tep_alloc(); + if (!tep) + return NULL; + + if (tracecmd_fill_local_events_system(tracing_dir, tep, sys_names, NULL)) { + tep_free(tep); + tep = NULL; + } + + return tep; +} + +/** + * tracecmd_local_events - create a pevent from the events on system + * @tracing_dir: The directory that contains the events. + * + * Returns a pevent structure that contains the pevents local to + * the system. + */ +struct tep_handle *tracecmd_local_events(const char *tracing_dir) +{ + return tracecmd_local_events_system(tracing_dir, NULL); +} + +/** + * tracecmd_fill_local_events - Fill a pevent with the events on system + * @tracing_dir: The directory that contains the events. + * @pevent: Allocated pevent which will be filled + * @parsing_failures: return number of failures while parsing the event files + * + * Returns whether the operation succeeded + */ +int tracecmd_fill_local_events(const char *tracing_dir, + struct tep_handle *pevent, int *parsing_failures) +{ + return tracecmd_fill_local_events_system(tracing_dir, pevent, + NULL, parsing_failures); +} + /** * tracecmd_local_plugins - returns an array of available tracer plugins * @tracing_dir: The directory that contains the tracing directory From patchwork Wed Aug 28 08:57:39 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: "Tzvetomir Stoyanov (VMware)" X-Patchwork-Id: 11118305 Return-Path: Received: from mail.kernel.org (pdx-korg-mail-1.web.codeaurora.org [172.30.200.123]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id 5029914DE for ; Wed, 28 Aug 2019 08:57:53 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.kernel.org (Postfix) with ESMTP id 3011A2339E for ; Wed, 28 Aug 2019 08:57:53 +0000 (UTC) Authentication-Results: mail.kernel.org; dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b="NvMDTejl" Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1726429AbfH1I5w (ORCPT ); Wed, 28 Aug 2019 04:57:52 -0400 Received: from mail-wm1-f65.google.com ([209.85.128.65]:53259 "EHLO mail-wm1-f65.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1726259AbfH1I5w (ORCPT ); Wed, 28 Aug 2019 04:57:52 -0400 Received: by mail-wm1-f65.google.com with SMTP id 10so1868354wmp.3 for ; Wed, 28 Aug 2019 01:57:51 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20161025; h=from:to:cc:subject:date:message-id:in-reply-to:references :mime-version:content-transfer-encoding; bh=ur+VhcY0EeBF1+7rEL+sbjYCD3Z8tWJnvkXUHG7kPQw=; b=NvMDTejlW0ikzqZifsY4MeQMunNm3U7G7Mrxf7BHp8M/Kpa6KSn+k87htATqnRbDQz B5OwOub9CEGwd6J/PKbLw8nqxHeiyiWTJo/pUdjzxihbXdlRRz9yVnDJZC9LUuqbZCsz wt6DGnSfi4Ao23sUO4CvMgxox+stqccvY2cXeQseBveoUDc/oLnVa0I0t8NqBcSgjtCt tMDGsXcgXBchiuhkZDq58sfB5veXygZ9qiRFc0f0buFHNSTUu/uLXZiY9ZatUEBnV/q3 zj7mdnI3E5ApyPC7nALE0QU3uDZ3vJ3LVu8gw2wuSEswQnIhQXDiKY8qAGzV5p9kMqmY rD5w== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references:mime-version:content-transfer-encoding; bh=ur+VhcY0EeBF1+7rEL+sbjYCD3Z8tWJnvkXUHG7kPQw=; b=ThY+KzXok8cVAWlMRkgioUdDdjPxxYULTKnzwZGY85fs2rfgxMmKWVTceZ6MvqB8iX ThTNNAi8mbK3hi1YpVYg7Ww+b3tYSglFHbkp8DrokI3naDevs6GBIJ5oI7VC28tyV5id H7Ey+OilRIRZhUVXxHfhhD5Qj3Ju822csjwBMPFVAyG9SrC2fx/hsDQu9zze2mKqqx/K +ada0AJF9f7dsOcKfYEDB/IXJVgPD4XbGUsEKENfonvsnJeQx+8bVuZ9TgcIT/O5BGh8 vZmAL1o1IZ3TnjC+Nrd8IReL5qbVI3Yy76dh/rr8MBjLqk51tjIawWbksYpmWKKNRm8E 73vw== X-Gm-Message-State: APjAAAV//2uJ6+QCv+ihRlHimtYdMjfY3RkdQMjW6RqxummTs8gEVPhR qPgUQNmzNcfjmCJj+Viyq1g= X-Google-Smtp-Source: APXvYqx6e8w7r4m+hpki9vSncdpr5yCdohIuDEo06p85IfUJJHbFFFas9JJPslhEnoQGyGryv3/s0g== X-Received: by 2002:a05:600c:296:: with SMTP id 22mr3221731wmk.148.1566982670643; Wed, 28 Aug 2019 01:57:50 -0700 (PDT) Received: from oberon.eng.vmware.com ([146.247.46.5]) by smtp.gmail.com with ESMTPSA id u186sm2579433wmu.26.2019.08.28.01.57.49 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Wed, 28 Aug 2019 01:57:50 -0700 (PDT) From: "Tzvetomir Stoyanov (VMware)" To: rostedt@goodmis.org Cc: linux-trace-devel@vger.kernel.org Subject: [PATCH v12 2/9] trace-cmd: Added support for negative time offsets in trace.dat file Date: Wed, 28 Aug 2019 11:57:39 +0300 Message-Id: <20190828085746.26231-3-tz.stoyanov@gmail.com> X-Mailer: git-send-email 2.21.0 In-Reply-To: <20190828085746.26231-1-tz.stoyanov@gmail.com> References: <20190828085746.26231-1-tz.stoyanov@gmail.com> MIME-Version: 1.0 Sender: linux-trace-devel-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-trace-devel@vger.kernel.org From: Tzvetomir Stoyanov When synchronizing timestamps between different machines, there are cases when the time offset is negative. This patch changes the way time offset is written and read from trace.dat file - as signed decimal, instead of hex. Signed-off-by: Tzvetomir Stoyanov --- include/trace-cmd/trace-cmd.h | 2 +- lib/trace-cmd/trace-input.c | 6 +++--- tracecmd/trace-read.c | 4 ++-- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/include/trace-cmd/trace-cmd.h b/include/trace-cmd/trace-cmd.h index da29d53..c7cac98 100644 --- a/include/trace-cmd/trace-cmd.h +++ b/include/trace-cmd/trace-cmd.h @@ -129,7 +129,7 @@ int tracecmd_is_buffer_instance(struct tracecmd_input *handle); void tracecmd_create_top_instance(char *name); void tracecmd_remove_instances(void); -void tracecmd_set_ts_offset(struct tracecmd_input *handle, unsigned long long offset); +void tracecmd_set_ts_offset(struct tracecmd_input *handle, long long offset); void tracecmd_set_ts2secs(struct tracecmd_input *handle, unsigned long long hz); void tracecmd_print_events(struct tracecmd_input *handle, const char *regex); diff --git a/lib/trace-cmd/trace-input.c b/lib/trace-cmd/trace-input.c index 654101f..05e595f 100644 --- a/lib/trace-cmd/trace-input.c +++ b/lib/trace-cmd/trace-input.c @@ -90,7 +90,7 @@ struct tracecmd_input { bool read_page; bool use_pipe; struct cpu_data *cpu_data; - unsigned long long ts_offset; + long long ts_offset; double ts2secs; char * cpustats; char * uname; @@ -2121,7 +2121,7 @@ static int init_cpu(struct tracecmd_input *handle, int cpu) } void tracecmd_set_ts_offset(struct tracecmd_input *handle, - unsigned long long offset) + long long offset) { handle->ts_offset = offset; } @@ -2138,7 +2138,7 @@ void tracecmd_set_ts2secs(struct tracecmd_input *handle, static int handle_options(struct tracecmd_input *handle) { - unsigned long long offset; + long long offset; unsigned short option; unsigned int size; char *cpustats = NULL; diff --git a/tracecmd/trace-read.c b/tracecmd/trace-read.c index d22c723..8d98dd7 100644 --- a/tracecmd/trace-read.c +++ b/tracecmd/trace-read.c @@ -58,7 +58,7 @@ static struct list_head handle_list; struct input_files { struct list_head list; const char *file; - unsigned long long tsoffset; + long long tsoffset; unsigned long long ts2secs; }; static struct list_head input_files; @@ -1422,7 +1422,7 @@ void trace_report (int argc, char **argv) struct input_files *inputs; struct handle_list *handles; enum output_type otype; - unsigned long long tsoffset = 0; + long long tsoffset = 0; unsigned long long ts2secs = 0; unsigned long long ts2sc; int show_stat = 0; From patchwork Wed Aug 28 08:57:40 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: "Tzvetomir Stoyanov (VMware)" X-Patchwork-Id: 11118307 Return-Path: Received: from mail.kernel.org (pdx-korg-mail-1.web.codeaurora.org [172.30.200.123]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id 6D64314DE for ; Wed, 28 Aug 2019 08:57:54 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.kernel.org (Postfix) with ESMTP id 4D6DD23403 for ; Wed, 28 Aug 2019 08:57:54 +0000 (UTC) Authentication-Results: mail.kernel.org; dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b="JG6Z7Gxg" Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1726436AbfH1I5y (ORCPT ); Wed, 28 Aug 2019 04:57:54 -0400 Received: from mail-wm1-f65.google.com ([209.85.128.65]:40810 "EHLO mail-wm1-f65.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1726293AbfH1I5x (ORCPT ); Wed, 28 Aug 2019 04:57:53 -0400 Received: by mail-wm1-f65.google.com with SMTP id t9so805768wmi.5 for ; Wed, 28 Aug 2019 01:57:52 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20161025; h=from:to:cc:subject:date:message-id:in-reply-to:references :mime-version:content-transfer-encoding; bh=bJAVvyqSeoa1jAnD2+HN2Roj8blocYF3Ubt/w/PAf4I=; b=JG6Z7GxglODV+p68avG+73XPcrhgj3oQ8lEnHpbvry4Ex0rZq95XhLwNS4e1HUPfKa mUmQFNJ/NyukLkn29DDAhVGXiIUsN+pqPIFg2tE+28xABcL7sxLFj6Lz2YTL5Sij263S 2+Pzeh6FdCpnGxePElKrFMh3TcFz5IBwUeIh9Y5SoAe5hpleLMPyE3jiFPIFh5LNNQcH 4D5SdJQixXItITrUYIdqjBlsgRTmPvauZ3iKNmstnoFPvdDmta2MXp8+GQ5QA1fxNAIK a7tMZNTEin1f2+hIzC47mWkrmGYfv8NXu03unCfl5j6NPd6UP7z0pyF7eCco82ydbQd7 nZAw== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references:mime-version:content-transfer-encoding; bh=bJAVvyqSeoa1jAnD2+HN2Roj8blocYF3Ubt/w/PAf4I=; b=pkZUSLAKdZ6bqwxDQD4KX1WulCWf2B3Lk8ZWkYAG+F5YyBDbNBpdZfhy/kdUpO+idh /vixuTdRRb1vVwjzS8LoHlm2Se/0hnnGPk9YHrBwa3OXqH77nL9iSktuFdiiZzgGCi3j YGUYXePiznKuhorpIMfJWtDF4hWNsIt7bkc87b0G88N7uvEs1FW2xUoDsuT5oT5GKRps rYGtpnhZcZ3gLtmUmccc0b4Y0tmZhvizImQl67YBsd1p3MdKV6Q0pYcjDouTsjoGaJin mqWiZprn+WQ8VThkhR3QctQhw/EvVrHFdhSDvoiGXfU7VLHVPXQWyEvX0w4FfDL8tn2A L/1g== X-Gm-Message-State: APjAAAXoIOTw/yvpXMQTh9o6zwDVayaG8iDSsoLzG50RZgjzOf9Sfyv6 kQ5jKn69cO2DTkeoTE1mjzuXoefj X-Google-Smtp-Source: APXvYqxjdAKoC3a0p1bTDdAcbz8vL98NR9z7kLuc5KwLTCaxoZgpK7NY37hame73UXAAQV9L6+42Xw== X-Received: by 2002:a7b:c95a:: with SMTP id i26mr3559174wml.175.1566982671606; Wed, 28 Aug 2019 01:57:51 -0700 (PDT) Received: from oberon.eng.vmware.com ([146.247.46.5]) by smtp.gmail.com with ESMTPSA id u186sm2579433wmu.26.2019.08.28.01.57.50 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Wed, 28 Aug 2019 01:57:51 -0700 (PDT) From: "Tzvetomir Stoyanov (VMware)" To: rostedt@goodmis.org Cc: linux-trace-devel@vger.kernel.org Subject: [PATCH v12 3/9] trace-cmd: Fix tracecmd_read_page_record() to read more than one event Date: Wed, 28 Aug 2019 11:57:40 +0300 Message-Id: <20190828085746.26231-4-tz.stoyanov@gmail.com> X-Mailer: git-send-email 2.21.0 In-Reply-To: <20190828085746.26231-1-tz.stoyanov@gmail.com> References: <20190828085746.26231-1-tz.stoyanov@gmail.com> MIME-Version: 1.0 Sender: linux-trace-devel-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-trace-devel@vger.kernel.org From: Tzvetomir Stoyanov The kbuffer_next_event() will return the next event on the sub buffer. If we pass in the last_record to tracecmd_read_page_record(), it initializes the sub buffer, and by calling kbuffer_next_event() (instead of kbuffer_read_event()), the second event on the sub buffer is returned. This causes the match of the last_record not to match if the last_record happens to be the first event on the sub buffer. Signed-off-by: Tzvetomir Stoyanov --- lib/trace-cmd/trace-input.c | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/lib/trace-cmd/trace-input.c b/lib/trace-cmd/trace-input.c index 05e595f..3bb17f9 100644 --- a/lib/trace-cmd/trace-input.c +++ b/lib/trace-cmd/trace-input.c @@ -1720,18 +1720,22 @@ tracecmd_read_page_record(struct tep_handle *pevent, void *page, int size, goto out_free; } - do { + ptr = kbuffer_read_event(kbuf, &ts); + while (ptr < last_record->data) { ptr = kbuffer_next_event(kbuf, NULL); if (!ptr) break; - } while (ptr < last_record->data); + if (ptr == last_record->data) + break; + } if (ptr != last_record->data) { warning("tracecmd_read_page_record: could not find last_record"); goto out_free; } - } + ptr = kbuffer_next_event(kbuf, &ts); + } else + ptr = kbuffer_read_event(kbuf, &ts); - ptr = kbuffer_read_event(kbuf, &ts); if (!ptr) goto out_free; From patchwork Wed Aug 28 08:57:41 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: "Tzvetomir Stoyanov (VMware)" X-Patchwork-Id: 11118309 Return-Path: Received: from mail.kernel.org (pdx-korg-mail-1.web.codeaurora.org [172.30.200.123]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id 2453F1395 for ; Wed, 28 Aug 2019 08:57:55 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.kernel.org (Postfix) with ESMTP id 03B792339E for ; Wed, 28 Aug 2019 08:57:55 +0000 (UTC) Authentication-Results: mail.kernel.org; dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b="rrcJdT7L" Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1726438AbfH1I5y (ORCPT ); Wed, 28 Aug 2019 04:57:54 -0400 Received: from mail-wr1-f66.google.com ([209.85.221.66]:45472 "EHLO mail-wr1-f66.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1726259AbfH1I5y (ORCPT ); Wed, 28 Aug 2019 04:57:54 -0400 Received: by mail-wr1-f66.google.com with SMTP id q12so1608613wrj.12 for ; Wed, 28 Aug 2019 01:57:53 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20161025; h=from:to:cc:subject:date:message-id:in-reply-to:references :mime-version:content-transfer-encoding; bh=cvAw5cqGWJQCaxLK4o1tvUof4SkcEdE+z/wwuzAqZTM=; b=rrcJdT7LwBYT+tX8E0w8pBT29XRCFmIHxIMTymw/R/16lChpuoCAnbdLsg98tRMOwO ZdgHemeJsxcc8pyX+8k7lSHVb/4oDiZkeso365zRw/nZu7Mvk9Qqesor+zvrOEVfuQ8y eH4QHXufGR4v3pQsriszZODMINZcTwNyv5FZ2WfK1pIQ7gUuF9cIxY1PlWawleqTsfIF kYknupdiNLAqSfz5cC0xlqfbJKEcqYVIAbKE3559NqqnSyLsbSOVAxGzV6AAB9FeR030 Zl2EiP8xL3XRvoYIMSdXR+U6dvUC+b+jwtb53Y7yNCFDGvVR9WTzq+1N4arPpTwv9kgn sDjA== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references:mime-version:content-transfer-encoding; bh=cvAw5cqGWJQCaxLK4o1tvUof4SkcEdE+z/wwuzAqZTM=; b=bBtDJ1Jm/utYqLfY1SzryECzSjwlH5Ufi7P5o0IY9ZHF4qM/wjYQyZHdNY6awsgBlg VqdKQXZT4C3Da+z4EV4mDXVVYV51tkfH+UO3nVaaJBJNJkso5nTXkCmAh1iZEIV+Hl+g v5AqCZuIXT0iVe98Vyc4AXvNKWSWa+Zvf/lkhFRW4lj6rU5FhvigHRazW/A8yEePxhwM u6zoBNLEPbGHuh3v5pPKh2gPZStm4uEHxyyYS6PRiqRBW20Scut/ieht4kN8dgZs4QFt t2ejCkqoDfWPt4fwoNe/ktleOh96s+HxuN4jdHlFtjw537qL+lBxQLhVXh0J05zV8t1J hZXA== X-Gm-Message-State: APjAAAUDtbQNmSH0Mu8dYTe/1p811G7TVn3EZgJ8j27W8SQozah7Wg+3 GxZ6E6F2r+svy51hqbTOpMw= X-Google-Smtp-Source: APXvYqwxbznHPG48Zljyf5HZffAtrsY3/Ut7dyjWfo46WBwXoIOaiEOd5CaDuBJ9hPHl08JfXdTUcA== X-Received: by 2002:a5d:564f:: with SMTP id j15mr3111877wrw.326.1566982672568; Wed, 28 Aug 2019 01:57:52 -0700 (PDT) Received: from oberon.eng.vmware.com ([146.247.46.5]) by smtp.gmail.com with ESMTPSA id u186sm2579433wmu.26.2019.08.28.01.57.51 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Wed, 28 Aug 2019 01:57:52 -0700 (PDT) From: "Tzvetomir Stoyanov (VMware)" To: rostedt@goodmis.org Cc: linux-trace-devel@vger.kernel.org Subject: [PATCH v12 4/9] trace-cmd: Added implementation of htonll() and ntohll() Date: Wed, 28 Aug 2019 11:57:41 +0300 Message-Id: <20190828085746.26231-5-tz.stoyanov@gmail.com> X-Mailer: git-send-email 2.21.0 In-Reply-To: <20190828085746.26231-1-tz.stoyanov@gmail.com> References: <20190828085746.26231-1-tz.stoyanov@gmail.com> MIME-Version: 1.0 Sender: linux-trace-devel-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-trace-devel@vger.kernel.org From: Tzvetomir Stoyanov Added implementation of htonll() and ntohll() as macros, if they are not already defined. Signed-off-by: Tzvetomir Stoyanov --- tracecmd/include/trace-msg.h | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/tracecmd/include/trace-msg.h b/tracecmd/include/trace-msg.h index b7fe10b..445f799 100644 --- a/tracecmd/include/trace-msg.h +++ b/tracecmd/include/trace-msg.h @@ -15,4 +15,14 @@ extern unsigned int page_size; void plog(const char *fmt, ...); void pdie(const char *fmt, ...); +#ifndef htonll +# if __BYTE_ORDER == __LITTLE_ENDIAN +#define htonll(x) __bswap_64(x) +#define ntohll(x) __bswap_64(x) +#else +#define htonll(x) (x) +#define ntohll(x) (x) +#endif +#endif + #endif /* _TRACE_MSG_H_ */ From patchwork Wed Aug 28 08:57:42 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: "Tzvetomir Stoyanov (VMware)" X-Patchwork-Id: 11118311 Return-Path: Received: from mail.kernel.org (pdx-korg-mail-1.web.codeaurora.org [172.30.200.123]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id 3265714DE for ; Wed, 28 Aug 2019 08:57:57 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.kernel.org (Postfix) with ESMTP id 091FD23403 for ; Wed, 28 Aug 2019 08:57:57 +0000 (UTC) Authentication-Results: mail.kernel.org; dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b="vJ4sZINh" Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1726440AbfH1I54 (ORCPT ); Wed, 28 Aug 2019 04:57:56 -0400 Received: from mail-wm1-f67.google.com ([209.85.128.67]:37925 "EHLO mail-wm1-f67.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1726293AbfH1I54 (ORCPT ); Wed, 28 Aug 2019 04:57:56 -0400 Received: by mail-wm1-f67.google.com with SMTP id o184so1151112wme.3 for ; Wed, 28 Aug 2019 01:57:54 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20161025; h=from:to:cc:subject:date:message-id:in-reply-to:references :mime-version:content-transfer-encoding; bh=kMzqp+bMChPRFBScO3nEZo1UAkgmucpEFNlaVmBUOCc=; b=vJ4sZINh+soDfY5fclwXCIz1CVoWbBkftaq9xEeRQ7e68atvNIiHLAE+grmTrQjHlx sE5MJwcEgPnbQ2mf25VoBdS38xnCIk+GTNMFMrLYnZQQZtZq1gMq+8zWwmKXIZ3cL5Ye 8pEM0ujsKbkcB3pfEdm028GSNHurmDtMthwMgUcfStrs+DhL/RY8U76JhnvCtZK2cpgv LHpwlXM+PhyGkdBHufCur/ySxkIysXUhjMc3h2WErtmip6uGE/0v7+K1+u4lFy87pbsP /JpcoE7woCsbs/rDFgQeOxOA74aQDAqxgyvuT2DuQxlR+0CphO7fKtDbON+6NudT5VeJ 6NeA== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references:mime-version:content-transfer-encoding; bh=kMzqp+bMChPRFBScO3nEZo1UAkgmucpEFNlaVmBUOCc=; b=XpnWCQVsIV9c1UlNhY5O65LjftM+qS7hpH8hNsN6hHgSvourXOMo3GBIDBvqA297BK AGGee1UzlnEOsvP8fY+IR31j+oCLDewRRJTwvKTdHrfXKSQSHRQJxXvThhhmmJwzp+dt gtNAf6PBEzHTdAQAd+5s0epfLr8gJ+ZZyEkZT4UJBiUU66okpT1VsDXMHVi5vqrCojS2 CCfRbinNDPakQaXrctS5ASfPw+U9x9Vc1HzniSvKd6BnE8Z8hwtG9g1yT9LsI7ZhXkqH MB+V2tVLveLJshagPHORk82Wd2E3pdwCPneOWEz2BuNfq7b4VHPgfdtYLWvytuouPUus gGPA== X-Gm-Message-State: APjAAAU1R3loCK6rzMlUX44vJd1bIvafL4WYgk0/Vp9QotLjbpGln5ZK wL6mOp7pG35f6TM9QCjX2FozafLP X-Google-Smtp-Source: APXvYqys8Wi+iBeflzi8b/Twq8OnYBlAEOHxqXYKIM3Phf1blQWi6rOwVxT6VtM71SPEQ8V09UPFFQ== X-Received: by 2002:a1c:e710:: with SMTP id e16mr3579655wmh.38.1566982673487; Wed, 28 Aug 2019 01:57:53 -0700 (PDT) Received: from oberon.eng.vmware.com ([146.247.46.5]) by smtp.gmail.com with ESMTPSA id u186sm2579433wmu.26.2019.08.28.01.57.52 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Wed, 28 Aug 2019 01:57:52 -0700 (PDT) From: "Tzvetomir Stoyanov (VMware)" To: rostedt@goodmis.org Cc: linux-trace-devel@vger.kernel.org Subject: [PATCH v12 5/9] trace-cmd: Refactored few functions in trace-record.c Date: Wed, 28 Aug 2019 11:57:42 +0300 Message-Id: <20190828085746.26231-6-tz.stoyanov@gmail.com> X-Mailer: git-send-email 2.21.0 In-Reply-To: <20190828085746.26231-1-tz.stoyanov@gmail.com> References: <20190828085746.26231-1-tz.stoyanov@gmail.com> MIME-Version: 1.0 Sender: linux-trace-devel-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-trace-devel@vger.kernel.org From: Tzvetomir Stoyanov In order to reuse the code inside the trace-cmd application, few functions from trace-record.c are refactored: - make_instances() and tracecmd_remove_instances() are splited. New ones are created: tracecmd_make_instance() and tracecmd_remove_instance(), which are visible outside the trace-record.c - Following functions are made non-static: tracecmd_init_instance() get_instance_dir(), write_instance_file(), write_tracing_on(), tracecmd_set_clock() - New function is implemented: tracecmd_local_cpu_count(), an internal API to get local_cpu_count. Signed-off-by: Tzvetomir Stoyanov --- tracecmd/include/trace-local.h | 9 ++++ tracecmd/trace-record.c | 88 +++++++++++++++++++--------------- 2 files changed, 59 insertions(+), 38 deletions(-) diff --git a/tracecmd/include/trace-local.h b/tracecmd/include/trace-local.h index 29d0bf8..1d305bf 100644 --- a/tracecmd/include/trace-local.h +++ b/tracecmd/include/trace-local.h @@ -237,6 +237,15 @@ void update_first_instance(struct buffer_instance *instance, int topt); void show_instance_file(struct buffer_instance *instance, const char *name); int count_cpus(void); +void write_tracing_on(struct buffer_instance *instance, int on); +char *get_instance_dir(struct buffer_instance *instance); +int write_instance_file(struct buffer_instance *instance, + const char *file, const char *str, const char *type); +void tracecmd_init_instance(struct buffer_instance *instance); +void tracecmd_make_instance(struct buffer_instance *instance); +int tracecmd_local_cpu_count(void); +void tracecmd_set_clock(struct buffer_instance *instance); +void tracecmd_remove_instance(struct buffer_instance *instance); /* No longer in event-utils.h */ void __noreturn die(const char *fmt, ...); /* Can be overriden */ diff --git a/tracecmd/trace-record.c b/tracecmd/trace-record.c index e844029..db1d37a 100644 --- a/tracecmd/trace-record.c +++ b/tracecmd/trace-record.c @@ -186,7 +186,7 @@ static inline int no_top_instance(void) return first_instance != &top_instance; } -static void init_instance(struct buffer_instance *instance) +void tracecmd_init_instance(struct buffer_instance *instance) { instance->event_next = &instance->events; } @@ -311,7 +311,7 @@ static void reset_save_file_cond(const char *file, int prio, */ void add_instance(struct buffer_instance *instance, int cpu_count) { - init_instance(instance); + tracecmd_init_instance(instance); instance->next = buffer_instances; if (first_instance == buffer_instances) first_instance = instance; @@ -498,7 +498,7 @@ static void add_event(struct buffer_instance *instance, struct event_list *event static void reset_event_list(struct buffer_instance *instance) { instance->events = NULL; - init_instance(instance); + tracecmd_init_instance(instance); } static char *get_temp_file(struct buffer_instance *instance, int cpu) @@ -804,8 +804,7 @@ get_instance_file(struct buffer_instance *instance, const char *file) return path; } -static char * -get_instance_dir(struct buffer_instance *instance) +char *get_instance_dir(struct buffer_instance *instance) { char *buf; char *path; @@ -849,9 +848,8 @@ static int write_file(const char *file, const char *str, const char *type) return ret; } -static int -write_instance_file(struct buffer_instance *instance, - const char *file, const char *str, const char *type) +int write_instance_file(struct buffer_instance *instance, + const char *file, const char *str, const char *type) { char *path; int ret; @@ -1993,7 +1991,7 @@ static int open_tracing_on(struct buffer_instance *instance) return fd; } -static void write_tracing_on(struct buffer_instance *instance, int on) +void write_tracing_on(struct buffer_instance *instance, int on) { int ret; int fd; @@ -2320,7 +2318,7 @@ void tracecmd_enable_events(void) enable_events(first_instance); } -static void set_clock(struct buffer_instance *instance) +void tracecmd_set_clock(struct buffer_instance *instance) { char *path; char *content; @@ -4471,49 +4469,58 @@ static void clear_func_filters(void) } } -static void make_instances(void) +void tracecmd_make_instance(struct buffer_instance *instance) { - struct buffer_instance *instance; struct stat st; char *path; int ret; + path = get_instance_dir(instance); + ret = stat(path, &st); + if (ret < 0) { + ret = mkdir(path, 0777); + if (ret < 0) + die("mkdir %s", path); + } else + /* Don't delete instances that already exist */ + instance->flags |= BUFFER_FL_KEEP; + tracecmd_put_tracing_file(path); + +} + +static void make_instances(void) +{ + struct buffer_instance *instance; + for_each_instance(instance) { if (is_guest(instance)) continue; + tracecmd_make_instance(instance); + } +} - path = get_instance_dir(instance); - ret = stat(path, &st); - if (ret < 0) { - ret = mkdir(path, 0777); - if (ret < 0) - die("mkdir %s", path); - } else - /* Don't delete instances that already exist */ - instance->flags |= BUFFER_FL_KEEP; - tracecmd_put_tracing_file(path); +void tracecmd_remove_instance(struct buffer_instance *instance) +{ + char *path; + + if (instance->tracing_on_fd > 0) { + close(instance->tracing_on_fd); + instance->tracing_on_fd = 0; } + path = get_instance_dir(instance); + rmdir(path); + tracecmd_put_tracing_file(path); } void tracecmd_remove_instances(void) { struct buffer_instance *instance; - char *path; - int ret; for_each_instance(instance) { /* Only delete what we created */ if (is_guest(instance) || (instance->flags & BUFFER_FL_KEEP)) continue; - if (instance->tracing_on_fd > 0) { - close(instance->tracing_on_fd); - instance->tracing_on_fd = 0; - } - path = get_instance_dir(instance); - ret = rmdir(path); - if (ret < 0) - die("rmdir %s", path); - tracecmd_put_tracing_file(path); + tracecmd_remove_instance(instance); } } @@ -5008,7 +5015,7 @@ void trace_stop(int argc, char **argv) int topt = 0; struct buffer_instance *instance = &top_instance; - init_instance(instance); + tracecmd_init_instance(instance); for (;;) { int c; @@ -5049,7 +5056,7 @@ void trace_restart(int argc, char **argv) int topt = 0; struct buffer_instance *instance = &top_instance; - init_instance(instance); + tracecmd_init_instance(instance); for (;;) { int c; @@ -5091,7 +5098,7 @@ void trace_reset(int argc, char **argv) int topt = 0; struct buffer_instance *instance = &top_instance; - init_instance(instance); + tracecmd_init_instance(instance); /* if last arg is -a, then -b and -d apply to all instances */ int last_specified_all = 0; @@ -5175,11 +5182,16 @@ static void init_common_record_context(struct common_record_context *ctx, memset(ctx, 0, sizeof(*ctx)); ctx->instance = &top_instance; ctx->curr_cmd = curr_cmd; - init_instance(ctx->instance); + tracecmd_init_instance(ctx->instance); local_cpu_count = count_cpus(); ctx->instance->cpu_count = local_cpu_count; } +int tracecmd_local_cpu_count(void) +{ + return local_cpu_count; +} + #define IS_EXTRACT(ctx) ((ctx)->curr_cmd == CMD_extract) #define IS_START(ctx) ((ctx)->curr_cmd == CMD_start) #define IS_STREAM(ctx) ((ctx)->curr_cmd == CMD_stream) @@ -5762,7 +5774,7 @@ static void record_trace(int argc, char **argv, tracecmd_disable_all_tracing(1); for_all_instances(instance) - set_clock(instance); + tracecmd_set_clock(instance); /* Record records the date first */ if (ctx->date && From patchwork Wed Aug 28 08:57:43 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: "Tzvetomir Stoyanov (VMware)" X-Patchwork-Id: 11118313 Return-Path: Received: from mail.kernel.org (pdx-korg-mail-1.web.codeaurora.org [172.30.200.123]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id 5F32818B7 for ; Wed, 28 Aug 2019 08:57:57 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.kernel.org (Postfix) with ESMTP id 3F0C12342D for ; Wed, 28 Aug 2019 08:57:57 +0000 (UTC) Authentication-Results: mail.kernel.org; dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b="E9aQJmxc" Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1726293AbfH1I55 (ORCPT ); Wed, 28 Aug 2019 04:57:57 -0400 Received: from mail-wr1-f66.google.com ([209.85.221.66]:33756 "EHLO mail-wr1-f66.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1726259AbfH1I54 (ORCPT ); Wed, 28 Aug 2019 04:57:56 -0400 Received: by mail-wr1-f66.google.com with SMTP id u16so1663701wrr.0 for ; Wed, 28 Aug 2019 01:57:55 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20161025; h=from:to:cc:subject:date:message-id:in-reply-to:references :mime-version:content-transfer-encoding; bh=WDK+MrZiBymTI91BeSXyb/ij9m9Dyr5WqrTahcYK5D4=; b=E9aQJmxcn7w3w6vBidEYDXOTr4R1t8hEYP9XMmy9WYkfEY8asOhjAlM1RDpMj1IjnU MWCxeWfkNb59oPXyurKodHlk7JOlWT21XJn6Qse2XcFn0GJWroOdiAgAobsuFxvN3xLa mW8l0N7mU+ORZHXZq+p1vLJtTl2qo963dzDlL0dScruVkyqLxj3pz8OfOU/9HW314TEa xuis3iQ0sn1IVPgQgcGzbQJP0iubrQkxsS+ncnKsd0HwbmKKCheWYTNoinYUkCnJZ06t 2zks91dphj8xPHwDnnJ1QPCDeE8Y1oXlE0MFsr/0tq1riicbiUgKGBa+BHqotoMp34ZK u4UA== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references:mime-version:content-transfer-encoding; bh=WDK+MrZiBymTI91BeSXyb/ij9m9Dyr5WqrTahcYK5D4=; b=j8xahXRt/npCnSRBqvhV6dqDeSE0JQqIDfuj8LU22NTNtniID6Ac+Ryj2Q8RY/gedn +f8Ux2kLSqjyNixWISS4qjqNSY0mzUvycKA1HMAWIj0zhK29LhZjH768jWxukHN++xma l3VipWR24dAVQRJGkQMjap6XToxNoOQUlyfBpgIh7GRe7s1R1OW+pT/XJU9WFuOFKYLc nAgGUde0cyA4z1GZ5e03GSRy63yuaVrmQbyB12rKd++9tyVh5Q86diyS/kT31TZeqJcA fGQz2ad8p5+ze/4bxs1rwgAaQiRvv//MMli9vf6qlgFAxiYjWLutbsUpeVfD9eszlxIt 2stw== X-Gm-Message-State: APjAAAXNYzgIh3HrDZR6u3nXGeaHzk21JoscHRH11CgCkjFFFRdFJiiX +AQA4dM+joXA5PCsDuiRSRY= X-Google-Smtp-Source: APXvYqx9malN13MVfv5ig1O6TDndZ9COYb6JpN6i9Hvvdpu6fP566xenAgRlSvJbmXa3p4QxeTLzCQ== X-Received: by 2002:a5d:4f81:: with SMTP id d1mr3247961wru.177.1566982674489; Wed, 28 Aug 2019 01:57:54 -0700 (PDT) Received: from oberon.eng.vmware.com ([146.247.46.5]) by smtp.gmail.com with ESMTPSA id u186sm2579433wmu.26.2019.08.28.01.57.53 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Wed, 28 Aug 2019 01:57:53 -0700 (PDT) From: "Tzvetomir Stoyanov (VMware)" To: rostedt@goodmis.org Cc: linux-trace-devel@vger.kernel.org Subject: [PATCH v12 6/9] trace-cmd: Find and store pids of tasks, which run virtual CPUs of given VM Date: Wed, 28 Aug 2019 11:57:43 +0300 Message-Id: <20190828085746.26231-7-tz.stoyanov@gmail.com> X-Mailer: git-send-email 2.21.0 In-Reply-To: <20190828085746.26231-1-tz.stoyanov@gmail.com> References: <20190828085746.26231-1-tz.stoyanov@gmail.com> MIME-Version: 1.0 Sender: linux-trace-devel-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-trace-devel@vger.kernel.org From: Tzvetomir Stoyanov In order to match host and guest events, a mapping between guest VCPU and the host task, running this VCPU is needed. Extended existing struct guest to hold such mapping and added logic in read_qemu_guests() function to initialize it. Implemented a new internal API, get_guest_vcpu_pid(), to retrieve VCPU-task mapping for given VM. Signed-off-by: Tzvetomir Stoyanov --- tracecmd/include/trace-local.h | 1 + tracecmd/trace-record.c | 57 ++++++++++++++++++++++++++++++++++ 2 files changed, 58 insertions(+) diff --git a/tracecmd/include/trace-local.h b/tracecmd/include/trace-local.h index 1d305bf..a4166b8 100644 --- a/tracecmd/include/trace-local.h +++ b/tracecmd/include/trace-local.h @@ -247,6 +247,7 @@ int tracecmd_local_cpu_count(void); void tracecmd_set_clock(struct buffer_instance *instance); void tracecmd_remove_instance(struct buffer_instance *instance); +int get_guest_vcpu_pid(unsigned int guest_cid, unsigned int guest_vcpu); /* No longer in event-utils.h */ void __noreturn die(const char *fmt, ...); /* Can be overriden */ void *malloc_or_die(unsigned int size); /* Can be overridden */ diff --git a/tracecmd/trace-record.c b/tracecmd/trace-record.c index db1d37a..c30a57e 100644 --- a/tracecmd/trace-record.c +++ b/tracecmd/trace-record.c @@ -2795,10 +2795,12 @@ static bool is_digits(const char *s) return true; } +#define VCPUS_MAX 256 struct guest { char *name; int cid; int pid; + int cpu_pid[VCPUS_MAX]; }; static struct guest *guests; @@ -2816,6 +2818,46 @@ static char *get_qemu_guest_name(char *arg) return arg; } +static void read_qemu_guests_pids(char *guest_task, struct guest *guest) +{ + struct dirent *entry; + char path[PATH_MAX]; + char *buf = NULL; + size_t n = 0; + int vcpu; + DIR *dir; + FILE *f; + + snprintf(path, sizeof(path), "/proc/%s/task", guest_task); + dir = opendir(path); + if (!dir) + return; + + while ((entry = readdir(dir))) { + if (!(entry->d_type == DT_DIR && is_digits(entry->d_name))) + continue; + + snprintf(path, sizeof(path), "/proc/%s/task/%s/comm", + guest_task, entry->d_name); + f = fopen(path, "r"); + if (!f) + continue; + if (getline(&buf, &n, f) < 0) + goto next; + if (strncmp(buf, "CPU ", 4) != 0) + goto next; + + vcpu = atoi(buf+4); + if (!(vcpu >= 0 && vcpu < VCPUS_MAX)) + goto next; + guest->cpu_pid[vcpu] = atoi(entry->d_name); + +next: + fclose(f); + } + free(buf); +} + static void read_qemu_guests(void) { static bool initialized; @@ -2879,6 +2921,8 @@ static void read_qemu_guests(void) if (!is_qemu) goto next; + read_qemu_guests_pids(entry->d_name, &guest); + guests = realloc(guests, (guests_len + 1) * sizeof(*guests)); if (!guests) die("Can not allocate guest buffer"); @@ -2996,6 +3040,19 @@ static char *parse_guest_name(char *guest, int *cid, int *port) return guest; } +int get_guest_vcpu_pid(unsigned int guest_cid, unsigned int guest_vcpu) +{ + int i; + + if (!guests || guest_vcpu >= VCPUS_MAX) + return -1; + + for (i = 0; i < guests_len; i++) + if (guest_cid == guests[i].cid) + return guests[i].cpu_pid[guest_vcpu]; + return -1; +} + static void set_prio(int prio) { struct sched_param sp; From patchwork Wed Aug 28 08:57:44 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: "Tzvetomir Stoyanov (VMware)" X-Patchwork-Id: 11118315 Return-Path: Received: from mail.kernel.org (pdx-korg-mail-1.web.codeaurora.org [172.30.200.123]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id 808721395 for ; Wed, 28 Aug 2019 08:57:58 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.kernel.org (Postfix) with ESMTP id 5735C23403 for ; Wed, 28 Aug 2019 08:57:58 +0000 (UTC) Authentication-Results: mail.kernel.org; dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b="KJEWsW4o" Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1726462AbfH1I56 (ORCPT ); Wed, 28 Aug 2019 04:57:58 -0400 Received: from mail-wm1-f65.google.com ([209.85.128.65]:37927 "EHLO mail-wm1-f65.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1726432AbfH1I55 (ORCPT ); Wed, 28 Aug 2019 04:57:57 -0400 Received: by mail-wm1-f65.google.com with SMTP id o184so1151217wme.3 for ; Wed, 28 Aug 2019 01:57:56 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20161025; h=from:to:cc:subject:date:message-id:in-reply-to:references :mime-version:content-transfer-encoding; bh=GbGYkEmYblBmNINRPa8aXQYJD8H6TCYdrUpYwcLE0Vg=; b=KJEWsW4oGOag8fFMGP2nHLf/hslTvWZcNnnkCKfZNO9RAzjm0NOviq9cLQgrSvLVzI c06bk/x5cOkOHueFg7O65iC49JBTNtK0/IsG3UQmBtrMUaUrrBNvJCQstQE+zHiakSXU +RzC1nsfD659ERqaibazj2j2R+8/ZfGRQRyqQJ98n5beFaJr2eReQ+yG148yum4+IA8q xwSjpVm+4yfsehOCl/9W5CHMyYpp9pD1xupQNptSt1qo2mFCwt/37bodBHRgzsfC+YJe xCyANwXX28hXnTfmmcBVSPQvX5WAhHY5iw+ubrVd7iQ2QzECBUNKVf2uA0t7ZMCwFY9U RDyw== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references:mime-version:content-transfer-encoding; bh=GbGYkEmYblBmNINRPa8aXQYJD8H6TCYdrUpYwcLE0Vg=; b=Qf5Qfehpf48q1Ntq1JeNS5NBu4ENfbJw6HahBI/TcS+xctixCvZrGdoagDqkT17Gsj vDQCSO996PiIoL7pc/icAi/vTOmWiRksQ8bocdqUgL4KJC7yqZLU/kuXo2UBVrXbqSyj tPivRE9WIjpqQtyJWx1ObfRm8SOIJiZGNCbNxSIT8FgovG9eMW/ANxj6qKT5T/FvTadN 9S0ZMDBS0dhr7x6ZTXwzRqOPaivyIdKTA5/Fx3G4gjOZ+tCnEnj+YK/dRi5X/VuDWTv4 NHNxgsBw7LsFHU6G+iwxdo4owqKxGl2Fj0jv47sxV5Kv2s2HXux/EyIbQnjz6uoJrB+j op/g== X-Gm-Message-State: APjAAAWutmRXljyXoSjYImzwtxHtEbUMcPdxZ33oVD/L7XYtXD03au9a W2TTKxO1OD70aVCJaFwhBog= X-Google-Smtp-Source: APXvYqwpmJcoiNfTKfbpX7JTB5KUoJxUD6ju+y9nXDuXce3XjMnGbyQxrLmi3VDryGLCmRGWXVw6ww== X-Received: by 2002:a7b:c775:: with SMTP id x21mr3638106wmk.90.1566982675481; Wed, 28 Aug 2019 01:57:55 -0700 (PDT) Received: from oberon.eng.vmware.com ([146.247.46.5]) by smtp.gmail.com with ESMTPSA id u186sm2579433wmu.26.2019.08.28.01.57.54 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Wed, 28 Aug 2019 01:57:54 -0700 (PDT) From: "Tzvetomir Stoyanov (VMware)" To: rostedt@goodmis.org Cc: linux-trace-devel@vger.kernel.org Subject: [PATCH v12 7/9] trace-cmd: Implemented new API tracecmd_add_option_v() Date: Wed, 28 Aug 2019 11:57:44 +0300 Message-Id: <20190828085746.26231-8-tz.stoyanov@gmail.com> X-Mailer: git-send-email 2.21.0 In-Reply-To: <20190828085746.26231-1-tz.stoyanov@gmail.com> References: <20190828085746.26231-1-tz.stoyanov@gmail.com> MIME-Version: 1.0 Sender: linux-trace-devel-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-trace-devel@vger.kernel.org From: Tzvetomir Stoyanov This patch implements a new tracecmd API, tracecmd_add_option_v() It adds new option in trace.dat, similar to tracecmd_add_option(), but the option's data is passed as list of buffers. The standard struct iovec is used as input parameter, containing the option's data buffers. Signed-off-by: Tzvetomir Stoyanov --- include/trace-cmd/trace-cmd.h | 5 ++ include/traceevent/event-parse.h | 1 + tracecmd/trace-output.c | 114 +++++++++++++++++++++++++++---- 3 files changed, 105 insertions(+), 15 deletions(-) diff --git a/include/trace-cmd/trace-cmd.h b/include/trace-cmd/trace-cmd.h index c7cac98..6f7bc2e 100644 --- a/include/trace-cmd/trace-cmd.h +++ b/include/trace-cmd/trace-cmd.h @@ -249,11 +249,16 @@ struct tracecmd_output *tracecmd_create_init_file_override(const char *output_fi struct tracecmd_option *tracecmd_add_option(struct tracecmd_output *handle, unsigned short id, int size, const void *data); +struct tracecmd_option * +tracecmd_add_option_v(struct tracecmd_output *handle, + unsigned short id, const struct iovec *vector, int count); + struct tracecmd_option *tracecmd_add_buffer_option(struct tracecmd_output *handle, const char *name, int cpus); int tracecmd_write_cpus(struct tracecmd_output *handle, int cpus); int tracecmd_write_options(struct tracecmd_output *handle); +int tracecmd_append_options(struct tracecmd_output *handle); int tracecmd_update_option(struct tracecmd_output *handle, struct tracecmd_option *option, int size, const void *data); diff --git a/include/traceevent/event-parse.h b/include/traceevent/event-parse.h index 65cabd9..b7bda12 100644 --- a/include/traceevent/event-parse.h +++ b/include/traceevent/event-parse.h @@ -11,6 +11,7 @@ #include #include #include +#include #include "traceevent/trace-seq.h" diff --git a/tracecmd/trace-output.c b/tracecmd/trace-output.c index 33d6ce3..41fb037 100644 --- a/tracecmd/trace-output.c +++ b/tracecmd/trace-output.c @@ -883,22 +883,25 @@ static struct tracecmd_output *create_file(const char *output_file, } /** - * tracecmd_add_option - add options to the file + * tracecmd_add_option_v - add options to the file * @handle: the output file handle name * @id: the id of the option * @size: the size of the option data * @data: the data to write to the file. + * @vector: array of vectors, pointing to the data to write in the file + * @count: number of items in the vector array * * Returns handle to update option if needed. * Just the content can be updated, with smaller or equal to * content than the specified size. */ struct tracecmd_option * -tracecmd_add_option(struct tracecmd_output *handle, - unsigned short id, int size, const void *data) +tracecmd_add_option_v(struct tracecmd_output *handle, + unsigned short id, const struct iovec *vector, int count) { struct tracecmd_option *option; - + char *data = NULL; + int i, size = 0; /* * We can only add options before they were written. * This may change in the future. @@ -906,32 +909,63 @@ tracecmd_add_option(struct tracecmd_output *handle, if (handle->options_written) return NULL; - handle->nr_options++; + for (i = 0; i < count; i++) + size += vector[i].iov_len; + /* Some IDs (like TRACECMD_OPTION_TRACECLOCK) pass vector with 0 / NULL data */ + if (size) { + data = malloc(size); + if (!data) { + warning("Insufficient memory"); + return NULL; + } + } option = malloc(sizeof(*option)); if (!option) { warning("Could not allocate space for option"); + free(data); return NULL; } - option->id = id; - option->size = size; - option->data = malloc(size); - if (!option->data) { - warning("Insufficient memory"); - free(option); - return NULL; + handle->nr_options++; + option->data = data; + for (i = 0; i < count; i++) { + if (vector[i].iov_base && vector[i].iov_len) { + memcpy(data, vector[i].iov_base, vector[i].iov_len); + data += vector[i].iov_len; + } } - /* Some IDs (like TRACECMD_OPTION_TRACECLOCK) pass 0 / NULL data */ - if (size) - memcpy(option->data, data, size); + option->size = size; + option->id = id; list_add_tail(&option->list, &handle->options); return option; } +/** + * tracecmd_add_option - add options to the file + * @handle: the output file handle name + * @id: the id of the option + * @size: the size of the option data + * @data: the data to write to the file. + * + * Returns handle to update option if needed. + * Just the content can be updated, with smaller or equal to + * content than the specified size. + */ +struct tracecmd_option * +tracecmd_add_option(struct tracecmd_output *handle, + unsigned short id, int size, const void *data) +{ + struct iovec vect; + + vect.iov_base = (void *) data; + vect.iov_len = size; + return tracecmd_add_option_v(handle, id, &vect, 1); +} + int tracecmd_write_cpus(struct tracecmd_output *handle, int cpus) { cpus = convert_endian_4(handle, cpus); @@ -979,6 +1013,56 @@ int tracecmd_write_options(struct tracecmd_output *handle) return 0; } +int tracecmd_append_options(struct tracecmd_output *handle) +{ + struct tracecmd_option *options; + unsigned short option; + unsigned short endian2; + unsigned int endian4; + off_t offset; + int r; + + /* If already written, ignore */ + if (handle->options_written) + return 0; + + if (lseek64(handle->fd, 0, SEEK_END) == (off_t)-1) + return -1; + offset = lseek64(handle->fd, -2, SEEK_CUR); + if (offset == (off_t)-1) + return -1; + + r = pread(handle->fd, &option, 2, offset); + if (r != 2 || option != TRACECMD_OPTION_DONE) + return -1; + + list_for_each_entry(options, &handle->options, list) { + endian2 = convert_endian_2(handle, options->id); + if (do_write_check(handle, &endian2, 2)) + return -1; + + endian4 = convert_endian_4(handle, options->size); + if (do_write_check(handle, &endian4, 4)) + return -1; + + /* Save the data location in case it needs to be updated */ + options->offset = lseek64(handle->fd, 0, SEEK_CUR); + + if (do_write_check(handle, options->data, + options->size)) + return -1; + } + + option = TRACECMD_OPTION_DONE; + + if (do_write_check(handle, &option, 2)) + return -1; + + handle->options_written = 1; + + return 0; +} + int tracecmd_update_option(struct tracecmd_output *handle, struct tracecmd_option *option, int size, const void *data) From patchwork Wed Aug 28 08:57:45 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: "Tzvetomir Stoyanov (VMware)" X-Patchwork-Id: 11118317 Return-Path: Received: from mail.kernel.org (pdx-korg-mail-1.web.codeaurora.org [172.30.200.123]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id 26ACD1395 for ; Wed, 28 Aug 2019 08:58:00 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.kernel.org (Postfix) with ESMTP id F0A512189D for ; Wed, 28 Aug 2019 08:57:59 +0000 (UTC) Authentication-Results: mail.kernel.org; dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b="JXbA/KJ0" Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1726449AbfH1I57 (ORCPT ); Wed, 28 Aug 2019 04:57:59 -0400 Received: from mail-wr1-f65.google.com ([209.85.221.65]:46324 "EHLO mail-wr1-f65.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1726259AbfH1I57 (ORCPT ); Wed, 28 Aug 2019 04:57:59 -0400 Received: by mail-wr1-f65.google.com with SMTP id z1so1607224wru.13 for ; Wed, 28 Aug 2019 01:57:57 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20161025; h=from:to:cc:subject:date:message-id:in-reply-to:references :mime-version:content-transfer-encoding; bh=bsSiUlLbkTiBJEfghxW68sYmB/mqaE3O66hKCM23NFk=; b=JXbA/KJ0wzeacwzrNz7VXQi1zh35udgR2HN2TjcbomjWlXALcOiZIktTE6q/XLIfd3 pILDq1Nxcyl9J6E0m3rdbsCMxRppYqfj9kqFCIyk3b9K9R80j8ILaFJUPw5k8qFnm6fZ rdIU8vFZozqLaaH/+uYN4RmCSMNYWr5dvW0O+mNup1AWoe3RWDZbSUGxhb4iZfWRqzXT hfPmoDGyO2l5j2vdYIG3MSmxGJtPhBIWi+6FmFPyTKoq6dKR/kGezMbtuIyFAqrI+BF9 6To18hg9WIl+YxjNpc/WriAUo6yC/RGkVQSdRNeYxcJIqBrwvMZexO/hjuozh3L3KuiB jGoQ== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references:mime-version:content-transfer-encoding; bh=bsSiUlLbkTiBJEfghxW68sYmB/mqaE3O66hKCM23NFk=; b=sClkaAFUvBPplNVPT5beDavnE8h4Hqtzp+beO4diYqonSqDvXbAeWyc27VjNNgtoF8 WOIVYgR7IB8BTB54TULq3SvBi2BMM9ne+kH7ngGdt4KpyNcK2VnHurAc+PJFkVGFe0Mc 5HxEAUbU5M/IqemKS7opKJvu4TkiQKAU55+C0RtOf5vmCPGKYRZ3LexACHp6A8VwnGAs zHfKpx3gUS1/vUWJEdlqXeSrFmasLGzWWScpyWQC/6ipQs9jdLq1fOXFDhAVXMtJjrxA 1MG9f3QPMgi6bkCHTPXuPOL7JwlVk5ej5KmFRXHqc61IUXodhI2Mg1e9Ho3mWBVJLyUE PbTQ== X-Gm-Message-State: APjAAAU9h0QrJ6OTJgtyYWIDXAV5w/OAw07HeXzJNuv71zp/g/bF8ShX gtLbDm0l+/DVD8ky+XTQJTU= X-Google-Smtp-Source: APXvYqyr777MSfZt2wenBFs46bV3In3V/kbfKVFywFaNwkbTYdraTVbSPxmKOBGvAD2Unaj0yaExcA== X-Received: by 2002:a5d:5591:: with SMTP id i17mr3203547wrv.280.1566982676403; Wed, 28 Aug 2019 01:57:56 -0700 (PDT) Received: from oberon.eng.vmware.com ([146.247.46.5]) by smtp.gmail.com with ESMTPSA id u186sm2579433wmu.26.2019.08.28.01.57.55 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Wed, 28 Aug 2019 01:57:55 -0700 (PDT) From: "Tzvetomir Stoyanov (VMware)" To: rostedt@goodmis.org Cc: linux-trace-devel@vger.kernel.org Subject: [PATCH v12 8/9] trace-cmd: Implemented new option in trace.dat file: TRACECMD_OPTION_TIME_SHIFT Date: Wed, 28 Aug 2019 11:57:45 +0300 Message-Id: <20190828085746.26231-9-tz.stoyanov@gmail.com> X-Mailer: git-send-email 2.21.0 In-Reply-To: <20190828085746.26231-1-tz.stoyanov@gmail.com> References: <20190828085746.26231-1-tz.stoyanov@gmail.com> MIME-Version: 1.0 Sender: linux-trace-devel-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-trace-devel@vger.kernel.org From: Tzvetomir Stoyanov The TRACECMD_OPTION_TIME_SHIFT is used when synchronizing trace time stamps between two trace.dat files. It contains multiple long long (time, offset) pairs, describing time stamps _offset_, measured in the given local _time_. The content of the option buffer is: first 4 bytes - integer, count of timestamp offsets long long array of size _count_, local time in which the offset is measured long long array of size _count_, offset of the time stamps Signed-off-by: Tzvetomir Stoyanov --- include/trace-cmd/trace-cmd.h | 1 + lib/trace-cmd/trace-input.c | 127 +++++++++++++++++++++++++++++++++- 2 files changed, 126 insertions(+), 2 deletions(-) diff --git a/include/trace-cmd/trace-cmd.h b/include/trace-cmd/trace-cmd.h index 6f7bc2e..c202773 100644 --- a/include/trace-cmd/trace-cmd.h +++ b/include/trace-cmd/trace-cmd.h @@ -84,6 +84,7 @@ enum { TRACECMD_OPTION_OFFSET, TRACECMD_OPTION_CPUCOUNT, TRACECMD_OPTION_VERSION, + TRACECMD_OPTION_TIME_SHIFT, }; enum { diff --git a/lib/trace-cmd/trace-input.c b/lib/trace-cmd/trace-input.c index 3bb17f9..5a5fe3b 100644 --- a/lib/trace-cmd/trace-input.c +++ b/lib/trace-cmd/trace-input.c @@ -74,6 +74,11 @@ struct input_buffer_instance { size_t offset; }; +struct ts_offset_sample { + long long time; + long long offset; +}; + struct tracecmd_input { struct tep_handle *pevent; struct tep_plugin_list *plugin_list; @@ -91,6 +96,8 @@ struct tracecmd_input { bool use_pipe; struct cpu_data *cpu_data; long long ts_offset; + int ts_samples_count; + struct ts_offset_sample *ts_samples; double ts2secs; char * cpustats; char * uname; @@ -1069,6 +1076,66 @@ static void free_next(struct tracecmd_input *handle, int cpu) free_record(record); } +static inline unsigned long long +timestamp_correction_calc(unsigned long long ts, struct ts_offset_sample *min, + struct ts_offset_sample *max) +{ + long long tscor = min->offset + + (((((long long)ts) - min->time)* + (max->offset-min->offset))/(max->time-min->time)); + + if (tscor < 0) + return ts - llabs(tscor); + + return ts + tscor; + +} + +static unsigned long long timestamp_correct(unsigned long long ts, + struct tracecmd_input *handle) +{ + int min, mid, max; + + if (handle->ts_offset) + return ts + handle->ts_offset; + if (!handle->ts_samples_count || !handle->ts_samples) + return ts; + + /* We have one sample, nothing to calc here */ + if (handle->ts_samples_count == 1) + return ts + handle->ts_samples[0].offset; + + /* We have two samples, nothing to search here */ + if (handle->ts_samples_count == 2) + return timestamp_correction_calc(ts, &handle->ts_samples[0], + &handle->ts_samples[1]); + + /* We have more than two samples */ + if (ts <= handle->ts_samples[0].time) + return timestamp_correction_calc(ts, + &handle->ts_samples[0], + &handle->ts_samples[1]); + else if (ts >= handle->ts_samples[handle->ts_samples_count-1].time) + return timestamp_correction_calc(ts, + &handle->ts_samples[handle->ts_samples_count-2], + &handle->ts_samples[handle->ts_samples_count-1]); + min = 0; + max = handle->ts_samples_count-1; + mid = (min + max)/2; + while (min <= max) { + if (ts < handle->ts_samples[mid].time) + max = mid - 1; + else if (ts > handle->ts_samples[mid].time) + min = mid + 1; + else + break; + mid = (min + max)/2; + } + + return timestamp_correction_calc(ts, &handle->ts_samples[mid], + &handle->ts_samples[mid+1]); +} + /* * Page is mapped, now read in the page header info. */ @@ -1090,7 +1157,7 @@ static int update_page_info(struct tracecmd_input *handle, int cpu) kbuffer_subbuffer_size(kbuf)); return -1; } - handle->cpu_data[cpu].timestamp = kbuffer_timestamp(kbuf) + handle->ts_offset; + handle->cpu_data[cpu].timestamp = timestamp_correct(kbuffer_timestamp(kbuf), handle); if (handle->ts2secs) handle->cpu_data[cpu].timestamp *= handle->ts2secs; @@ -1817,7 +1884,7 @@ read_again: goto read_again; } - handle->cpu_data[cpu].timestamp = ts + handle->ts_offset; + handle->cpu_data[cpu].timestamp = timestamp_correct(ts, handle); if (handle->ts2secs) { handle->cpu_data[cpu].timestamp *= handle->ts2secs; @@ -2140,6 +2207,42 @@ void tracecmd_set_ts2secs(struct tracecmd_input *handle, handle->use_trace_clock = false; } +static int tsync_offset_cmp(const void *a, const void *b) +{ + struct ts_offset_sample *ts_a = (struct ts_offset_sample *)a; + struct ts_offset_sample *ts_b = (struct ts_offset_sample *)b; + + if (ts_a->time > ts_b->time) + return 1; + if (ts_a->time < ts_b->time) + return -1; + return 0; +} + +static void tsync_offset_load(struct tracecmd_input *handle, char *buf) +{ + int i, j; + long long *buf8 = (long long *)buf; + + for (i = 0; i < handle->ts_samples_count; i++) { + handle->ts_samples[i].time = tep_read_number(handle->pevent, + buf8+i, 8); + handle->ts_samples[i].offset = tep_read_number(handle->pevent, + buf8+handle->ts_samples_count+i, 8); + } + qsort(handle->ts_samples, + handle->ts_samples_count, sizeof(struct ts_offset_sample), + tsync_offset_cmp); + /* Filter possible samples with equal time */ + for (i = 0, j = 0; i < handle->ts_samples_count; i++) { + if (i == 0 || + handle->ts_samples[i].time != handle->ts_samples[i-1].time) { + handle->ts_samples[j++] = handle->ts_samples[i]; + } + } + handle->ts_samples_count = j; +} + static int handle_options(struct tracecmd_input *handle) { long long offset; @@ -2150,6 +2253,7 @@ static int handle_options(struct tracecmd_input *handle) struct input_buffer_instance *buffer; struct hook_list *hook; char *buf; + int sampes_size; int cpus; for (;;) { @@ -2194,6 +2298,25 @@ static int handle_options(struct tracecmd_input *handle) offset = strtoll(buf, NULL, 0); handle->ts_offset += offset; break; + case TRACECMD_OPTION_TIME_SHIFT: + /* + * int (4 bytes) count of timestamp offsets. + * long long array of size [count] of times, + * when the offsets were calculated. + * long long array of size [count] of timestamp offsets. + */ + if (handle->flags & TRACECMD_FL_IGNORE_DATE) + break; + handle->ts_samples_count = tep_read_number(handle->pevent, + buf, 4); + sampes_size = (8*handle->ts_samples_count); + if (size != (4+(2*sampes_size))) + break; + handle->ts_samples = malloc(2*sampes_size); + if (!handle->ts_samples) + return -ENOMEM; + tsync_offset_load(handle, buf+4); + break; case TRACECMD_OPTION_CPUSTAT: buf[size-1] = '\n'; cpustats = realloc(cpustats, cpustats_size + size + 1); From patchwork Wed Aug 28 08:57:46 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: "Tzvetomir Stoyanov (VMware)" X-Patchwork-Id: 11118319 Return-Path: Received: from mail.kernel.org (pdx-korg-mail-1.web.codeaurora.org [172.30.200.123]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id 0248414DE for ; Wed, 28 Aug 2019 08:58:05 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.kernel.org (Postfix) with ESMTP id AF3082339E for ; Wed, 28 Aug 2019 08:58:04 +0000 (UTC) Authentication-Results: mail.kernel.org; dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b="pZRByy0v" Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1726444AbfH1I6E (ORCPT ); Wed, 28 Aug 2019 04:58:04 -0400 Received: from mail-wm1-f68.google.com ([209.85.128.68]:37613 "EHLO mail-wm1-f68.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1726432AbfH1I6E (ORCPT ); Wed, 28 Aug 2019 04:58:04 -0400 Received: by mail-wm1-f68.google.com with SMTP id d16so1966781wme.2 for ; Wed, 28 Aug 2019 01:57:58 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20161025; h=from:to:cc:subject:date:message-id:in-reply-to:references :mime-version:content-transfer-encoding; bh=M6hNPT9GeIuzZOFlElB8gBNZGbnWlojTAMZWSKmruT0=; b=pZRByy0vNsn12Tsi9mjdX8jg7+IbTebhYlfU5LrpkvccN5HknWsjVkQTe4G4+NmTWb q3UOhAm4AtuMT4XAkE3PsJlswwSrKq2VzAzZvIPvpzWQc4WlMUucOd+7yhhw0oreUP0D lLT48nyE4+dI6N0qtHm1p6JaLknNJ/jx/QEpOWzgNmgpDmAVaSGtz8f0DTG4XivgE+3F dFBrF8EhCHSyIFRuFgAaQsXO7j6Bs4OHxtN2PPt9mYx5fVtrmaKE+ybUSHYA7yI545vm NTDpO2eVWc/WJ28fBLjyh47pYoNZPGG0q6HojJc3+1eZI0XYSHIMlaDCAndmPUp3boNx cJRA== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references:mime-version:content-transfer-encoding; bh=M6hNPT9GeIuzZOFlElB8gBNZGbnWlojTAMZWSKmruT0=; b=iY9/fVnPxNMDq5OEFjt96qvEJcojCw12H/7YqUSnXFunkdrJqlpO4L09aElh602SIZ Nq+Bjnasq4pH14/utPi+4pDFPlO8ipleus9UItbMlbRT4JB6bIkCwbpSrJYpH0QmuFcL WvN+BCliNmqF9qIV2kmI15DEviSfu/NI29685z+Fy6yDri4k/PnIwLMCaaAmd5Sn4xFT 1CJecAlJMdaHrUSyS1m9bZug55HKJJQrLfjGO7zoAo1z8UJJU7dn0hVapzFhENVHiPiE eUswypykKTJBns5iuVBVjOWBhKaREdwz0RydQpaPKKLYpilAsUiQWRAKU8vEicP1sa47 pkRg== X-Gm-Message-State: APjAAAXNKXZWUgeB4AWki4nF+zCJQAPourjnkNILv6qEoA3gUJNpoEjq ixmH0HvcRJmiLAwWE9D1nm8yOgBd X-Google-Smtp-Source: APXvYqw835WbiehP/s+gaa9fJs4rY3VL6NUEhunwFScYn4dsqZ1k9Gyw005rgJn1astOis6Ov1osMg== X-Received: by 2002:a7b:c758:: with SMTP id w24mr3527076wmk.143.1566982677662; Wed, 28 Aug 2019 01:57:57 -0700 (PDT) Received: from oberon.eng.vmware.com ([146.247.46.5]) by smtp.gmail.com with ESMTPSA id u186sm2579433wmu.26.2019.08.28.01.57.56 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Wed, 28 Aug 2019 01:57:56 -0700 (PDT) From: "Tzvetomir Stoyanov (VMware)" To: rostedt@goodmis.org Cc: linux-trace-devel@vger.kernel.org Subject: [PATCH v12 9/9] trace-cmd [POC]: Implemented timestamps synch algorithm, using vsock events. Date: Wed, 28 Aug 2019 11:57:46 +0300 Message-Id: <20190828085746.26231-10-tz.stoyanov@gmail.com> X-Mailer: git-send-email 2.21.0 In-Reply-To: <20190828085746.26231-1-tz.stoyanov@gmail.com> References: <20190828085746.26231-1-tz.stoyanov@gmail.com> MIME-Version: 1.0 Sender: linux-trace-devel-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-trace-devel@vger.kernel.org From: Tzvetomir Stoyanov This is a POC patch, implementing an algorithm for syncing timestamps between host and guest machines, using vsock trace events to catch the host / guest time. Signed-off-by: Tzvetomir Stoyanov --- include/trace-cmd/trace-cmd.h | 20 +- tracecmd/Makefile | 1 + tracecmd/include/trace-local.h | 32 +- tracecmd/trace-agent.c | 13 +- tracecmd/trace-msg.c | 210 ++++++++- tracecmd/trace-record.c | 79 +++- tracecmd/trace-timesync.c | 810 +++++++++++++++++++++++++++++++++ 7 files changed, 1130 insertions(+), 35 deletions(-) create mode 100644 tracecmd/trace-timesync.c diff --git a/include/trace-cmd/trace-cmd.h b/include/trace-cmd/trace-cmd.h index c202773..c5515c9 100644 --- a/include/trace-cmd/trace-cmd.h +++ b/include/trace-cmd/trace-cmd.h @@ -347,17 +347,29 @@ bool tracecmd_msg_done(struct tracecmd_msg_handle *msg_handle); void tracecmd_msg_set_done(struct tracecmd_msg_handle *msg_handle); int tracecmd_msg_send_trace_req(struct tracecmd_msg_handle *msg_handle, - int argc, char **argv, bool use_fifos); + int argc, char **argv, bool use_fifos, + bool do_tsync); int tracecmd_msg_recv_trace_req(struct tracecmd_msg_handle *msg_handle, - int *argc, char ***argv, bool *use_fifos); + int *argc, char ***argv, bool *use_fifos, + bool *do_tsync); int tracecmd_msg_send_trace_resp(struct tracecmd_msg_handle *msg_handle, int nr_cpus, int page_size, - unsigned int *ports, bool use_fifos); + unsigned int *ports, bool use_fifos, + bool do_tsync); int tracecmd_msg_recv_trace_resp(struct tracecmd_msg_handle *msg_handle, int *nr_cpus, int *page_size, - unsigned int **ports, bool *use_fifos); + unsigned int **ports, bool *use_fifos, + bool *do_tsync); +struct tracecmd_clock_sync; + +int tracecmd_msg_rcv_time_sync(struct tracecmd_msg_handle *msg_handle, + struct tracecmd_clock_sync *clock_sync, + long long *offset, long long *timestamp); +int tracecmd_msg_snd_time_sync(struct tracecmd_msg_handle *msg_handle, + struct tracecmd_clock_sync *clock_sync, + long long *offset, long long *timestamp); /* --- Plugin handling --- */ extern struct tep_plugin_option trace_ftrace_options[]; diff --git a/tracecmd/Makefile b/tracecmd/Makefile index 46af5cc..45da92c 100644 --- a/tracecmd/Makefile +++ b/tracecmd/Makefile @@ -32,6 +32,7 @@ TRACE_CMD_OBJS += trace-list.o TRACE_CMD_OBJS += trace-output.o TRACE_CMD_OBJS += trace-usage.o TRACE_CMD_OBJS += trace-msg.o +TRACE_CMD_OBJS += trace-timesync.o ifeq ($(VSOCK_DEFINED), 1) TRACE_CMD_OBJS += trace-agent.o diff --git a/tracecmd/include/trace-local.h b/tracecmd/include/trace-local.h index a4166b8..f2b3162 100644 --- a/tracecmd/include/trace-local.h +++ b/tracecmd/include/trace-local.h @@ -101,7 +101,7 @@ void trace_usage(int argc, char **argv); int trace_record_agent(struct tracecmd_msg_handle *msg_handle, int cpus, int *fds, - int argc, char **argv, bool use_fifos); + int argc, char **argv, bool use_fifos, bool do_tsync); struct hook_list; @@ -216,6 +216,12 @@ struct buffer_instance { unsigned int port; int *fds; bool use_fifos; + bool do_tsync; + + struct tracecmd_clock_sync *clock_sync; + int time_sync_count; + long long *time_sync_ts; + long long *time_sync_offsets; }; extern struct buffer_instance top_instance; @@ -237,6 +243,30 @@ void update_first_instance(struct buffer_instance *instance, int topt); void show_instance_file(struct buffer_instance *instance, const char *name); int count_cpus(void); + +struct tracecmd_time_sync_event { + int id; + int cpu; + int pid; + unsigned long long ts; +}; + +int tracecmd_clock_get_peer(struct tracecmd_clock_sync *clock_context, + unsigned int *remote_cid, unsigned int *remote_port); +bool tracecmd_time_sync_check(void); +void tracecmd_clock_context_free(struct buffer_instance *instance); +int tracecmd_clock_find_event(struct tracecmd_clock_sync *clock, int cpu, + struct tracecmd_time_sync_event *event); +void tracecmd_clock_synch_enable(struct tracecmd_clock_sync *clock_context); +void tracecmd_clock_synch_disable(struct tracecmd_clock_sync *clock_context); +void tracecmd_clock_synch_calc_reset(struct tracecmd_clock_sync *clock_context); +void tracecmd_clock_synch_calc_probe(struct tracecmd_clock_sync *clock_context, + long long ts_local, long long ts_remote); +int tracecmd_clock_synch_calc(struct tracecmd_clock_sync *clock_context, + long long *offset_ret, long long *time_ret); +void sync_time_with_host_v3(struct buffer_instance *instance); +void sync_time_with_guest_v3(struct buffer_instance *instance); + void write_tracing_on(struct buffer_instance *instance, int on); char *get_instance_dir(struct buffer_instance *instance); int write_instance_file(struct buffer_instance *instance, diff --git a/tracecmd/trace-agent.c b/tracecmd/trace-agent.c index 6cd6491..8433a48 100644 --- a/tracecmd/trace-agent.c +++ b/tracecmd/trace-agent.c @@ -132,6 +132,7 @@ static void agent_handle(int sd, int nr_cpus, int page_size) char **argv = NULL; int argc = 0; bool use_fifos; + bool do_tsync; int *fds; int ret; @@ -144,7 +145,8 @@ static void agent_handle(int sd, int nr_cpus, int page_size) if (!msg_handle) die("Failed to allocate message handle"); - ret = tracecmd_msg_recv_trace_req(msg_handle, &argc, &argv, &use_fifos); + ret = tracecmd_msg_recv_trace_req(msg_handle, &argc, &argv, + &use_fifos, &do_tsync); if (ret < 0) die("Failed to receive trace request"); @@ -153,13 +155,18 @@ static void agent_handle(int sd, int nr_cpus, int page_size) if (!use_fifos) make_vsocks(nr_cpus, fds, ports); + if (do_tsync) { + do_tsync = tracecmd_time_sync_check(); + if (!do_tsync) + warning("Failed to negotiate timestamps synchronization with the host"); + } ret = tracecmd_msg_send_trace_resp(msg_handle, nr_cpus, page_size, - ports, use_fifos); + ports, use_fifos, do_tsync); if (ret < 0) die("Failed to send trace response"); - trace_record_agent(msg_handle, nr_cpus, fds, argc, argv, use_fifos); + trace_record_agent(msg_handle, nr_cpus, fds, argc, argv, use_fifos, do_tsync); free(argv[0]); free(argv); diff --git a/tracecmd/trace-msg.c b/tracecmd/trace-msg.c index 35a48c2..bfe7e43 100644 --- a/tracecmd/trace-msg.c +++ b/tracecmd/trace-msg.c @@ -26,8 +26,12 @@ #include "trace-local.h" #include "trace-msg.h" +typedef __u16 u16; +typedef __s16 s16; typedef __u32 u32; typedef __be32 be32; +typedef __u64 u64; +typedef __s64 s64; static inline void dprint(const char *fmt, ...) { @@ -50,6 +54,9 @@ static inline void dprint(const char *fmt, ...) unsigned int page_size; +/* Try a few times to get an accurate time sync */ +#define TSYNC_TRIES 300 + struct tracecmd_msg_tinit { be32 cpus; be32 page_size; @@ -71,6 +78,19 @@ struct tracecmd_msg_trace_resp { be32 page_size; } __attribute__((packed)); +struct tracecmd_msg_tsync_stop { + long long offset; + long long timestamp; +} __attribute__((packed)); + +struct tracecmd_msg_tsync_req { + u16 cpu; +} __attribute__((packed)); + +struct tracecmd_msg_tsync_resp { + u64 time; +} __attribute__((packed)); + struct tracecmd_msg_header { be32 size; be32 cmd; @@ -78,15 +98,20 @@ struct tracecmd_msg_header { } __attribute__((packed)); #define MSG_MAP \ - C(CLOSE, 0, 0), \ - C(TINIT, 1, sizeof(struct tracecmd_msg_tinit)), \ - C(RINIT, 2, sizeof(struct tracecmd_msg_rinit)), \ - C(SEND_DATA, 3, 0), \ - C(FIN_DATA, 4, 0), \ - C(NOT_SUPP, 5, 0), \ - C(TRACE_REQ, 6, sizeof(struct tracecmd_msg_trace_req)), \ - C(TRACE_RESP, 7, sizeof(struct tracecmd_msg_trace_resp)),\ - C(CLOSE_RESP, 8, 0), + C(CLOSE, 0, 0), \ + C(TINIT, 1, sizeof(struct tracecmd_msg_tinit)), \ + C(RINIT, 2, sizeof(struct tracecmd_msg_rinit)), \ + C(SEND_DATA, 3, 0), \ + C(FIN_DATA, 4, 0), \ + C(NOT_SUPP, 5, 0), \ + C(TRACE_REQ, 6, sizeof(struct tracecmd_msg_trace_req)), \ + C(TRACE_RESP, 7, sizeof(struct tracecmd_msg_trace_resp)),\ + C(CLOSE_RESP, 8, 0), \ + C(TSYNC_START, 9, 0), \ + C(TSYNC_STOP, 10, sizeof(struct tracecmd_msg_tsync_stop)),\ + C(TSYNC_PROBE, 11, 0), \ + C(TSYNC_REQ, 12, sizeof(struct tracecmd_msg_tsync_req)), \ + C(TSYNC_RESP, 13, sizeof(struct tracecmd_msg_tsync_resp)), #undef C #define C(a,b,c) MSG_##a = b @@ -116,10 +141,13 @@ static const char *cmd_to_name(int cmd) struct tracecmd_msg { struct tracecmd_msg_header hdr; union { - struct tracecmd_msg_tinit tinit; - struct tracecmd_msg_rinit rinit; - struct tracecmd_msg_trace_req trace_req; - struct tracecmd_msg_trace_resp trace_resp; + struct tracecmd_msg_tinit tinit; + struct tracecmd_msg_rinit rinit; + struct tracecmd_msg_trace_req trace_req; + struct tracecmd_msg_trace_resp trace_resp; + struct tracecmd_msg_tsync_stop ts_stop; + struct tracecmd_msg_tsync_req ts_req; + struct tracecmd_msg_tsync_resp ts_resp; }; char *buf; } __attribute__((packed)); @@ -158,6 +186,7 @@ static int msg_write(int fd, struct tracecmd_msg *msg) enum msg_trace_flags { MSG_TRACE_USE_FIFOS = 1 << 0, + MSG_TRACE_DO_TSYNC = 1 << 1, }; static int make_tinit(struct tracecmd_msg_handle *msg_handle, @@ -811,7 +840,8 @@ int tracecmd_msg_wait_close_resp(struct tracecmd_msg_handle *msg_handle) return tracecmd_msg_wait_for_cmd(msg_handle, MSG_CLOSE_RESP); } -static int make_trace_req(struct tracecmd_msg *msg, int argc, char **argv, bool use_fifos) +static int make_trace_req(struct tracecmd_msg *msg, int argc, char **argv, + bool use_fifos, bool do_tsync) { size_t args_size = 0; char *p; @@ -821,7 +851,12 @@ static int make_trace_req(struct tracecmd_msg *msg, int argc, char **argv, bool args_size += strlen(argv[i]) + 1; msg->hdr.size = htonl(ntohl(msg->hdr.size) + args_size); - msg->trace_req.flags = use_fifos ? htonl(MSG_TRACE_USE_FIFOS) : htonl(0); + msg->trace_req.flags = 0; + if (use_fifos) + msg->trace_req.flags |= MSG_TRACE_USE_FIFOS; + if (do_tsync) + msg->trace_req.flags |= MSG_TRACE_DO_TSYNC; + msg->trace_req.flags = htonl(msg->trace_req.flags); msg->trace_req.argc = htonl(argc); msg->buf = calloc(args_size, 1); if (!msg->buf) @@ -835,13 +870,14 @@ static int make_trace_req(struct tracecmd_msg *msg, int argc, char **argv, bool } int tracecmd_msg_send_trace_req(struct tracecmd_msg_handle *msg_handle, - int argc, char **argv, bool use_fifos) + int argc, char **argv, bool use_fifos, + bool do_tsync) { struct tracecmd_msg msg; int ret; tracecmd_msg_init(MSG_TRACE_REQ, &msg); - ret = make_trace_req(&msg, argc, argv, use_fifos); + ret = make_trace_req(&msg, argc, argv, use_fifos, do_tsync); if (ret < 0) return ret; @@ -854,7 +890,8 @@ int tracecmd_msg_send_trace_req(struct tracecmd_msg_handle *msg_handle, * free(argv); */ int tracecmd_msg_recv_trace_req(struct tracecmd_msg_handle *msg_handle, - int *argc, char ***argv, bool *use_fifos) + int *argc, char ***argv, bool *use_fifos, + bool *do_tsync) { struct tracecmd_msg msg; char *p, *buf_end, **args; @@ -901,6 +938,7 @@ int tracecmd_msg_recv_trace_req(struct tracecmd_msg_handle *msg_handle, *argc = nr_args; *argv = args; *use_fifos = ntohl(msg.trace_req.flags) & MSG_TRACE_USE_FIFOS; + *do_tsync = ntohl(msg.trace_req.flags) & MSG_TRACE_DO_TSYNC; /* * On success we're passing msg.buf to the caller through argv[0] so we @@ -920,8 +958,125 @@ out: return ret; } +int tracecmd_msg_rcv_time_sync(struct tracecmd_msg_handle *msg_handle, + struct tracecmd_clock_sync *clock_context, + long long *offset, long long *timestamp) +{ + struct tracecmd_time_sync_event event; + unsigned int remote_cid = 0; + struct tracecmd_msg msg; + int cpu_pid, ret; + + if (clock_context == NULL || msg_handle == NULL) + return 0; + + if (offset) + *offset = 0; + + ret = tracecmd_msg_recv(msg_handle->fd, &msg); + if (ret < 0 || ntohl(msg.hdr.cmd) == MSG_TSYNC_STOP) + return 0; + if (ntohl(msg.hdr.cmd) != MSG_TSYNC_START) { + handle_unexpected_msg(msg_handle, &msg); + return 0; + } + + tracecmd_clock_get_peer(clock_context, &remote_cid, NULL); + tracecmd_msg_init(MSG_TSYNC_START, &msg); + tracecmd_msg_send(msg_handle->fd, &msg); + tracecmd_clock_synch_enable(clock_context); + + do { + memset(&event, 0, sizeof(event)); + ret = tracecmd_msg_recv(msg_handle->fd, &msg); + if (ret < 0 || ntohl(msg.hdr.cmd) == MSG_TSYNC_STOP) + break; + if (ntohl(msg.hdr.cmd) != MSG_TSYNC_PROBE) { + handle_unexpected_msg(msg_handle, &msg); + break; + } + ret = tracecmd_msg_recv(msg_handle->fd, &msg); + if (ret < 0 || ntohl(msg.hdr.cmd) == MSG_TSYNC_STOP) + break; + if (ntohl(msg.hdr.cmd) != MSG_TSYNC_REQ) { + handle_unexpected_msg(msg_handle, &msg); + break; + } + /* Get kvm event related to the corresponding VCPU context */ + cpu_pid = get_guest_vcpu_pid(remote_cid, ntohs(msg.ts_req.cpu)); + tracecmd_clock_find_event(clock_context, cpu_pid, &event); + tracecmd_msg_init(MSG_TSYNC_RESP, &msg); + msg.ts_resp.time = htonll(event.ts); + tracecmd_msg_send(msg_handle->fd, &msg); + } while (true); + + tracecmd_clock_synch_disable(clock_context); + + if (ret >= 0 && ntohl(msg.hdr.cmd) == MSG_TSYNC_STOP) { + if (offset) + *offset = ntohll(msg.ts_stop.offset); + if (timestamp) + *timestamp = ntohll(msg.ts_stop.timestamp); + } + + msg_free(&msg); + return 0; +} + +int tracecmd_msg_snd_time_sync(struct tracecmd_msg_handle *msg_handle, + struct tracecmd_clock_sync *clock_context, + long long *offset, long long *timestamp) +{ + struct tracecmd_time_sync_event event; + int sync_loop = TSYNC_TRIES; + struct tracecmd_msg msg; + int ret; + + if (clock_context == NULL || msg_handle == NULL) + return 0; + + tracecmd_msg_init(MSG_TSYNC_START, &msg); + tracecmd_msg_send(msg_handle->fd, &msg); + ret = tracecmd_msg_recv(msg_handle->fd, &msg); + if (ret < 0 || ntohl(msg.hdr.cmd) != MSG_TSYNC_START) + return 0; + tracecmd_clock_synch_calc_reset(clock_context); + tracecmd_clock_synch_enable(clock_context); + + do { + tracecmd_msg_init(MSG_TSYNC_PROBE, &msg); + tracecmd_msg_send(msg_handle->fd, &msg); + /* Get the ts and CPU of the sent event */ + ret = tracecmd_clock_find_event(clock_context, -1, &event); + tracecmd_msg_init(MSG_TSYNC_REQ, &msg); + msg.ts_req.cpu = htons(event.cpu); + tracecmd_msg_send(msg_handle->fd, &msg); + memset(&msg, 0, sizeof(msg)); + ret = tracecmd_msg_recv(msg_handle->fd, &msg); + if (ret < 0) + break; + if (ntohl(msg.hdr.cmd) != MSG_TSYNC_RESP) { + handle_unexpected_msg(msg_handle, &msg); + break; + } + tracecmd_clock_synch_calc_probe(clock_context, + event.ts, + htonll(msg.ts_resp.time)); + } while (--sync_loop); + + tracecmd_clock_synch_disable(clock_context); + tracecmd_clock_synch_calc(clock_context, offset, timestamp); + tracecmd_msg_init(MSG_TSYNC_STOP, &msg); + msg.ts_stop.offset = htonll(*offset); + msg.ts_stop.timestamp = htonll(*timestamp); + tracecmd_msg_send(msg_handle->fd, &msg); + + msg_free(&msg); + return 0; +} + static int make_trace_resp(struct tracecmd_msg *msg, int page_size, int nr_cpus, - unsigned int *ports, bool use_fifos) + unsigned int *ports, bool use_fifos, bool do_tsync) { int data_size; @@ -932,7 +1087,13 @@ static int make_trace_resp(struct tracecmd_msg *msg, int page_size, int nr_cpus, write_uints(msg->buf, data_size, ports, nr_cpus); msg->hdr.size = htonl(ntohl(msg->hdr.size) + data_size); - msg->trace_resp.flags = use_fifos ? htonl(MSG_TRACE_USE_FIFOS) : htonl(0); + msg->trace_resp.flags = 0; + if (use_fifos) + msg->trace_resp.flags |= MSG_TRACE_USE_FIFOS; + if (do_tsync) + msg->trace_resp.flags |= MSG_TRACE_DO_TSYNC; + msg->trace_resp.flags = htonl(msg->trace_resp.flags); + msg->trace_resp.cpus = htonl(nr_cpus); msg->trace_resp.page_size = htonl(page_size); @@ -941,13 +1102,14 @@ static int make_trace_resp(struct tracecmd_msg *msg, int page_size, int nr_cpus, int tracecmd_msg_send_trace_resp(struct tracecmd_msg_handle *msg_handle, int nr_cpus, int page_size, - unsigned int *ports, bool use_fifos) + unsigned int *ports, bool use_fifos, + bool do_tsync) { struct tracecmd_msg msg; int ret; tracecmd_msg_init(MSG_TRACE_RESP, &msg); - ret = make_trace_resp(&msg, page_size, nr_cpus, ports, use_fifos); + ret = make_trace_resp(&msg, page_size, nr_cpus, ports, use_fifos, do_tsync); if (ret < 0) return ret; @@ -956,7 +1118,8 @@ int tracecmd_msg_send_trace_resp(struct tracecmd_msg_handle *msg_handle, int tracecmd_msg_recv_trace_resp(struct tracecmd_msg_handle *msg_handle, int *nr_cpus, int *page_size, - unsigned int **ports, bool *use_fifos) + unsigned int **ports, bool *use_fifos, + bool *do_tsync) { struct tracecmd_msg msg; char *p, *buf_end; @@ -979,6 +1142,7 @@ int tracecmd_msg_recv_trace_resp(struct tracecmd_msg_handle *msg_handle, } *use_fifos = ntohl(msg.trace_resp.flags) & MSG_TRACE_USE_FIFOS; + *do_tsync = ntohl(msg.trace_resp.flags) & MSG_TRACE_DO_TSYNC; *nr_cpus = ntohl(msg.trace_resp.cpus); *page_size = ntohl(msg.trace_resp.page_size); *ports = calloc(*nr_cpus, sizeof(**ports)); diff --git a/tracecmd/trace-record.c b/tracecmd/trace-record.c index c30a57e..3947506 100644 --- a/tracecmd/trace-record.c +++ b/tracecmd/trace-record.c @@ -211,6 +211,8 @@ struct common_record_context { const char *output; char *date2ts; int data_flags; + int time_shift_count; + struct tracecmd_option *time_shift_option; int record_all; int total_disable; @@ -657,6 +659,11 @@ static void tell_guests_to_stop(void) if (is_guest(instance)) tracecmd_msg_send_close_msg(instance->msg_handle); } +} + +static void close_guests_handle(void) +{ + struct buffer_instance *instance; /* Wait for guests to acknowledge */ for_all_instances(instance) { @@ -3485,6 +3492,7 @@ static void connect_to_agent(struct buffer_instance *instance) unsigned int *ports; int i, *fds = NULL; bool use_fifos = false; + bool do_tsync, do_tsync_reply; if (!no_fifos) { nr_fifos = open_guest_fifos(instance->name, &fds); @@ -3496,20 +3504,26 @@ static void connect_to_agent(struct buffer_instance *instance) die("Failed to connect to vsocket @%u:%u", instance->cid, instance->port); + do_tsync = tracecmd_time_sync_check(); + msg_handle = tracecmd_msg_handle_alloc(sd, 0); if (!msg_handle) die("Failed to allocate message handle"); ret = tracecmd_msg_send_trace_req(msg_handle, instance->argc, - instance->argv, use_fifos); + instance->argv, use_fifos, do_tsync); if (ret < 0) die("Failed to send trace request"); ret = tracecmd_msg_recv_trace_resp(msg_handle, &nr_cpus, &page_size, - &ports, &use_fifos); + &ports, &use_fifos, &do_tsync_reply); if (ret < 0) die("Failed to receive trace response"); + if (do_tsync != do_tsync_reply) + warning("Failed to negotiate timestamps synchronization with the guest %s", + instance->name); + if (use_fifos) { if (nr_cpus != nr_fifos) { warning("number of FIFOs (%d) for guest %s differs " @@ -3527,10 +3541,13 @@ static void connect_to_agent(struct buffer_instance *instance) } instance->use_fifos = use_fifos; + instance->do_tsync = do_tsync_reply; instance->cpu_count = nr_cpus; /* the msg_handle now points to the guest fd */ instance->msg_handle = msg_handle; + + sync_time_with_guest_v3(instance); } static void setup_guest(struct buffer_instance *instance) @@ -3555,10 +3572,13 @@ static void setup_guest(struct buffer_instance *instance) close(fd); } -static void setup_agent(struct buffer_instance *instance, struct common_record_context *ctx) +static void setup_agent(struct buffer_instance *instance, + struct common_record_context *ctx) { struct tracecmd_output *network_handle; + sync_time_with_host_v3(instance); + network_handle = tracecmd_create_init_fd_msg(instance->msg_handle, listed_events); add_options(network_handle, ctx); @@ -5781,6 +5801,42 @@ static bool has_local_instances(void) } return false; } +#define TSYNC_DEBUG + +static void write_guest_time_shift(struct buffer_instance *instance) +{ + struct tracecmd_output *handle; + struct iovec vector[3]; + char *file; + int fd; + + if (!instance->time_sync_count) + return; + + file = get_guest_file(output_file, instance->name); + fd = open(file, O_RDWR); + if (fd < 0) + die("error opening %s", file); + put_temp_file(file); + handle = tracecmd_get_output_handle_fd(fd); + vector[0].iov_len = 4; + vector[0].iov_base = &instance->time_sync_count; + vector[1].iov_len = 8 * instance->time_sync_count; + vector[1].iov_base = instance->time_sync_ts; + vector[2].iov_len = 8 * instance->time_sync_count; + vector[2].iov_base = instance->time_sync_offsets; + tracecmd_add_option_v(handle, TRACECMD_OPTION_TIME_SHIFT, vector, 3); + tracecmd_append_options(handle); + tracecmd_output_close(handle); +#ifdef TSYNC_DEBUG + if (instance->time_sync_count > 1) + printf("\n\rDetected %lld ns ts offset drift in %lld ns for guest %s\n\r", + instance->time_sync_offsets[instance->time_sync_count-1] - + instance->time_sync_offsets[0], + instance->time_sync_ts[instance->time_sync_count-1]- + instance->time_sync_ts[0], instance->name); +#endif +} /* * This function contains common code for the following commands: @@ -5903,6 +5959,20 @@ static void record_trace(int argc, char **argv, if (!latency) wait_threads(); + if (ctx->instance && is_agent(ctx->instance)) { + sync_time_with_host_v3(ctx->instance); + tracecmd_clock_context_free(ctx->instance); + } else { + for_all_instances(instance) { + if (is_guest(instance)) { + sync_time_with_guest_v3(instance); + write_guest_time_shift(instance); + tracecmd_clock_context_free(instance); + } + } + } + close_guests_handle(); + if (IS_RECORD(ctx)) { record_data(ctx); delete_thread_data(); @@ -6043,7 +6113,7 @@ void trace_record(int argc, char **argv) int trace_record_agent(struct tracecmd_msg_handle *msg_handle, int cpus, int *fds, int argc, char **argv, - bool use_fifos) + bool use_fifos, bool do_tsync) { struct common_record_context ctx; char **argv_plus; @@ -6070,6 +6140,7 @@ int trace_record_agent(struct tracecmd_msg_handle *msg_handle, ctx.instance->fds = fds; ctx.instance->use_fifos = use_fifos; + ctx.instance->do_tsync = do_tsync; ctx.instance->flags |= BUFFER_FL_AGENT; ctx.instance->msg_handle = msg_handle; msg_handle->version = V3_PROTOCOL; diff --git a/tracecmd/trace-timesync.c b/tracecmd/trace-timesync.c new file mode 100644 index 0000000..37629c6 --- /dev/null +++ b/tracecmd/trace-timesync.c @@ -0,0 +1,810 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (C) 2019, VMware, Tzvetomir Stoyanov + * + */ + +#include +#include +#include +#include +#include +#include "trace-local.h" + +static int clock_sync_x86_host_init(struct tracecmd_clock_sync *clock_context); +static int clock_sync_x86_host_free(struct tracecmd_clock_sync *clock_context); +static int clock_sync_x86_host_find_events(struct tracecmd_clock_sync *clock, + int cpu, struct tracecmd_time_sync_event *event); +static int clock_sync_x86_guest_init(struct tracecmd_clock_sync *clock_context); +static int clock_sync_x86_guest_free(struct tracecmd_clock_sync *clock_context); +static int clock_sync_x86_guest_find_events(struct tracecmd_clock_sync *clock, + int pid, + struct tracecmd_time_sync_event *event); + +struct tracecmd_event_descr { + char *system; + char *name; +}; + +struct tracecmd_ftrace_param { + char *file; + char *set; + char *reset; +}; + +enum clock_sync_context { + CLOCK_KVM_X86_VSOCK_HOST, + CLOCK_KVM_X86_VSOCK_GUEST, + CLOCK_CONTEXT_MAX, +}; + +struct tracecmd_clock_sync { + enum clock_sync_context clock_context_id; + struct tracecmd_ftrace_param *ftrace_params; + struct tracecmd_time_sync_event *events; + int events_count; + struct tep_handle *tep; + struct buffer_instance *vinst; + + int probes_count; + int bad_probes; + int probes_size; + long long *times; + long long *offsets; + long long offset_av; + long long offset_min; + long long offset_max; + int debug_fd; + + unsigned int local_cid; + unsigned int local_port; + unsigned int remote_cid; + unsigned int remote_port; +}; + +struct { + const char *systems[3]; + struct tracecmd_ftrace_param ftrace_params[5]; + struct tracecmd_event_descr events[3]; + int (*clock_sync_init)(struct tracecmd_clock_sync *clock_context); + int (*clock_sync_free)(struct tracecmd_clock_sync *clock_context); + int (*clock_sync_find_events)(struct tracecmd_clock_sync *clock_context, + int pid, + struct tracecmd_time_sync_event *event); + int (*clock_sync_load)(struct tracecmd_clock_sync *clock_context); + int (*clock_sync_unload)(struct tracecmd_clock_sync *clock_context); +} static clock_sync[CLOCK_CONTEXT_MAX] = { + { /* CLOCK_KVM_X86_VSOCK_HOST */ + .systems = {"vsock", "ftrace", NULL}, + .ftrace_params = { + {"set_ftrace_filter", "vmx_read_l1_tsc_offset\nsvm_read_l1_tsc_offset", "\0"}, + {"current_tracer", "function", "nop"}, + {"events/vsock/virtio_transport_recv_pkt/enable", "1", "0"}, + {"events/vsock/virtio_transport_recv_pkt/filter", NULL, "\0"}, + {NULL, NULL, NULL} }, + .events = { + {.system = "ftrace", .name = "function"}, + {.system = "vsock", .name = "virtio_transport_recv_pkt"}, + {.system = NULL, .name = NULL} }, + clock_sync_x86_host_init, + clock_sync_x86_host_free, + clock_sync_x86_host_find_events, + }, + + { /* CLOCK_KVM_X86_VSOCK_GUEST */ + .systems = { "vsock", "ftrace", NULL}, + .ftrace_params = { + {"set_ftrace_filter", "vp_notify", "\0"}, + {"current_tracer", "function", "nop"}, + {"events/vsock/virtio_transport_alloc_pkt/enable", "1", "0"}, + {"events/vsock/virtio_transport_alloc_pkt/filter", NULL, "\0"}, + {NULL, NULL, NULL}, + }, + .events = { + {.system = "vsock", .name = "virtio_transport_alloc_pkt"}, + {.system = "ftrace", .name = "function"}, + {.system = NULL, .name = NULL} + }, + clock_sync_x86_guest_init, + clock_sync_x86_guest_free, + clock_sync_x86_guest_find_events, + } +}; + +static int clock_sync_x86_host_init(struct tracecmd_clock_sync *clock_context) +{ + char vsock_filter[255]; + + snprintf(vsock_filter, 255, + "src_cid==%u && src_port==%u && dst_cid==%u && dst_port==%u && len!=0", + clock_context->remote_cid, clock_context->remote_port, + clock_context->local_cid, clock_context->local_port); + + clock_context->ftrace_params[3].set = strdup(vsock_filter); + return 1; +} + +static int clock_sync_x86_host_free(struct tracecmd_clock_sync *clock_context) +{ + free(clock_context->ftrace_params[3].set); + clock_context->ftrace_params[3].set = NULL; + return 1; +} + +static int clock_sync_x86_guest_init(struct tracecmd_clock_sync *clock_context) +{ + char vsock_filter[255]; + + snprintf(vsock_filter, 255, + "src_cid==%u && src_port==%u && dst_cid==%u && dst_port==%u && len!=0", + clock_context->local_cid, clock_context->local_port, + clock_context->remote_cid, clock_context->remote_port); + + clock_context->ftrace_params[3].set = strdup(vsock_filter); + return 1; +} + +static int clock_sync_x86_guest_free(struct tracecmd_clock_sync *clock_context) +{ + free(clock_context->ftrace_params[3].set); + clock_context->ftrace_params[3].set = NULL; + return 1; +} + +static int +get_events_in_page(struct tep_handle *tep, void *page, + int size, int cpu, struct tracecmd_time_sync_event **events, + int *events_count, int *events_size) +{ + struct tracecmd_time_sync_event *events_array = NULL; + struct tep_record *last_record = NULL; + struct tep_event *event = NULL; + struct tep_record *record; + int id, cnt = 0; + + if (size <= 0) + return 0; + + if (*events == NULL) { + *events = malloc(10*sizeof(struct tracecmd_time_sync_event)); + *events_size = 10; + *events_count = 0; + } + + while (true) { + event = NULL; + record = tracecmd_read_page_record(tep, page, size, + last_record); + if (!record) + break; + free_record(last_record); + id = tep_data_type(tep, record); + event = tep_find_event(tep, id); + if (event) { + if (*events_count >= *events_size) { + events_array = realloc(*events, + ((3*(*events_size))/2)* + sizeof(struct tracecmd_time_sync_event)); + if (events_array) { + *events = events_array; + (*events_size) = (((*events_size)*3)/2); + } + } + + if (*events_count < *events_size) { + (*events)[*events_count].ts = record->ts; + (*events)[*events_count].cpu = cpu; + (*events)[*events_count].id = id; + (*events)[*events_count].pid = tep_data_pid(tep, record); + (*events_count)++; + cnt++; + } + } + last_record = record; + } + free_record(last_record); + + return cnt; +} + +static int sync_events_cmp(const void *a, const void *b) +{ + const struct tracecmd_time_sync_event *ea = (const struct tracecmd_time_sync_event *)a; + const struct tracecmd_time_sync_event *eb = (const struct tracecmd_time_sync_event *)b; + + if (ea->ts > eb->ts) + return 1; + if (ea->ts < eb->ts) + return -1; + return 0; +} + +static int find_sync_events(struct tep_handle *pevent, + struct tracecmd_time_sync_event *recorded, + int rsize, struct tracecmd_time_sync_event *events) +{ + int i = 0, j = 0; + + while (i < rsize) { + if (!events[j].ts && events[j].id == recorded[i].id && + (events[j].pid < 0 || events[j].pid == recorded[i].pid)) { + events[j].cpu = recorded[i].cpu; + events[j].ts = recorded[i].ts; + j++; + } else if (j > 0 && events[j-1].id == recorded[i].id && + (events[j-1].pid < 0 || events[j-1].pid == recorded[i].pid)) { + events[j-1].cpu = recorded[i].cpu; + events[j-1].ts = recorded[i].ts; + } + i++; + } + return j; +} + +//#define TSYNC_RBUFFER_DEBUG +static int find_raw_events(struct tep_handle *tep, + struct buffer_instance *instance, + struct tracecmd_time_sync_event *events) +{ + struct tracecmd_time_sync_event *events_array = NULL; + int events_count = 0; + int events_size = 0; + unsigned int p_size; + char file[PATH_MAX]; + int ts = 0; + void *page; + char *path; + int fd; + int i; + int r; + + p_size = getpagesize(); +#ifdef TSYNC_RBUFFER_DEBUG + file = get_instance_file(instance, "trace"); + if (!file) + return ts; + { + char *buf = NULL; + FILE *fp; + size_t n; + int r; + + printf("Events:\n\r"); + fp = fopen(file, "r"); + while ((r = getline(&buf, &n, fp)) >= 0) { + + if (buf[0] != '#') + printf("%s", buf); + free(buf); + buf = NULL; + } + fclose(fp); + } + tracecmd_put_tracing_file(file); +#endif /* TSYNC_RBUFFER_DEBUG */ + path = get_instance_file(instance, "per_cpu"); + if (!path) + return ts; + + page = malloc(p_size); + if (!page) + die("Failed to allocate time_stamp info"); + for (i = 0; i < instance->cpu_count; i++) { + sprintf(file, "%s/cpu%d/trace_pipe_raw", path, i); + fd = open(file, O_RDONLY | O_NONBLOCK); + if (fd < 0) + continue; + do { + r = read(fd, page, p_size); + if (r > 0) { + get_events_in_page(tep, page, r, i, + &events_array, &events_count, + &events_size); + } + } while (r > 0); + close(fd); + } + qsort(events_array, events_count, sizeof(*events_array), sync_events_cmp); + r = find_sync_events(tep, events_array, events_count, events); +#ifdef TSYNC_RBUFFER_DEBUG + len = 0; + while (events[len].id) { + printf("Found %d @ cpu %d: %lld pid %d\n\r", + events[len].id, events[len].cpu, + events[len].ts, events[len].pid); + len++; + } +#endif + + free(events_array); + free(page); + + tracecmd_put_tracing_file(path); + return r; +} + +static int clock_sync_x86_host_find_events(struct tracecmd_clock_sync *clock, + int pid, + struct tracecmd_time_sync_event *event) +{ + int ret; + + clock->events[0].pid = pid; + ret = find_raw_events(clock->tep, clock->vinst, clock->events); + event->ts = clock->events[0].ts; + event->cpu = clock->events[0].cpu; + return ret; + +} + +static int clock_sync_x86_guest_find_events(struct tracecmd_clock_sync *clock, + int pid, + struct tracecmd_time_sync_event *event) +{ + int ret; + + ret = find_raw_events(clock->tep, clock->vinst, clock->events); + if (ret != clock->events_count) + return 0; + event->ts = clock->events[1].ts; + event->cpu = clock->events[0].cpu; + return 1; + +} + +static void tracecmd_clock_sync_reset(struct tracecmd_clock_sync *clock_context) +{ + int i = 0; + + while (clock_context->events[i].id) { + clock_context->events[i].cpu = 0; + clock_context->events[i].ts = 0; + clock_context->events[i].pid = -1; + i++; + } +} + +int tracecmd_clock_find_event(struct tracecmd_clock_sync *clock, int pid, + struct tracecmd_time_sync_event *event) +{ + int ret = 0; + int id; + + if (clock == NULL || + clock->clock_context_id >= CLOCK_CONTEXT_MAX) + return 0; + + id = clock->clock_context_id; + if (clock_sync[id].clock_sync_find_events) + ret = clock_sync[id].clock_sync_find_events(clock, pid, event); + + tracecmd_clock_sync_reset(clock); + return ret; +} + +static void clock_context_copy(struct tracecmd_clock_sync *clock_context, + struct tracecmd_ftrace_param *params, + struct tracecmd_event_descr *events) +{ + int i; + + i = 0; + while (params[i].file) + i++; + clock_context->ftrace_params = calloc(i+1, sizeof(struct tracecmd_ftrace_param)); + i = 0; + while (params[i].file) { + clock_context->ftrace_params[i].file = strdup(params[i].file); + if (params[i].set) + clock_context->ftrace_params[i].set = strdup(params[i].set); + if (params[i].reset) + clock_context->ftrace_params[i].reset = strdup(params[i].reset); + i++; + } + + i = 0; + while (events[i].name) + i++; + clock_context->events = calloc(i+1, sizeof(struct tracecmd_time_sync_event)); + clock_context->events_count = i; +} + +void trace_instance_reset(struct buffer_instance *vinst) +{ + write_instance_file(vinst, "trace", "\0", NULL); +} + +static struct buffer_instance * +clock_synch_create_instance(const char *clock, unsigned int cid) +{ + struct buffer_instance *vinst; + char inst_name[256]; + + snprintf(inst_name, 256, "clock_synch-%d", cid); + + vinst = create_instance(strdup(inst_name)); + tracecmd_init_instance(vinst); + vinst->cpu_count = tracecmd_local_cpu_count(); + tracecmd_make_instance(vinst); + trace_instance_reset(vinst); + if (clock) + vinst->clock = strdup(clock); + tracecmd_set_clock(vinst); + return vinst; +} + +static struct tep_handle *clock_synch_get_tep(struct buffer_instance *instance, + const char * const *systems) +{ + struct tep_handle *tep = NULL; + char *path; + + path = get_instance_dir(instance); + tep = tracecmd_local_events_system(path, systems); + tracecmd_put_tracing_file(path); + + tep_set_file_bigendian(tep, tracecmd_host_bigendian()); + tep_set_local_bigendian(tep, tracecmd_host_bigendian()); + + return tep; +} + +static int get_vsocket_params(int fd, unsigned int *lcid, unsigned int *lport, + unsigned int *rcid, unsigned int *rport) +{ + struct sockaddr_vm addr; + socklen_t addr_len = sizeof(addr); + + memset(&addr, 0, sizeof(addr)); + if (getsockname(fd, (struct sockaddr *)&addr, &addr_len)) + return -1; + if (addr.svm_family != AF_VSOCK) + return -1; + *lport = addr.svm_port; + *lcid = addr.svm_cid; + + memset(&addr, 0, sizeof(addr)); + addr_len = sizeof(addr); + if (getpeername(fd, (struct sockaddr *)&addr, &addr_len)) + return -1; + if (addr.svm_family != AF_VSOCK) + return -1; + *rport = addr.svm_port; + *rcid = addr.svm_cid; + + return 0; +} + +#define TSYNC_DEBUG + +struct tracecmd_clock_sync* +tracecmd_clock_context_new(struct tracecmd_msg_handle *msg_handle, + const char *clock_str, + enum clock_sync_context id) +{ + struct tracecmd_clock_sync *clock_context; + struct tep_event *event; + unsigned int i = 0; + + switch (id) { +#ifdef VSOCK + case CLOCK_KVM_X86_VSOCK_HOST: + case CLOCK_KVM_X86_VSOCK_GUEST: + break; +#endif + default: /* not supported clock sync context */ + return NULL; + } + + if (id >= CLOCK_CONTEXT_MAX || NULL == msg_handle) + return NULL; + clock_context = calloc(1, sizeof(struct tracecmd_clock_sync)); + if (!clock_context) + return NULL; + if (get_vsocket_params(msg_handle->fd, + &clock_context->local_cid, + &clock_context->local_port, + &clock_context->remote_cid, + &clock_context->remote_port)) { + free (clock_context); + return NULL; + } + + clock_context->clock_context_id = id; + clock_context_copy(clock_context, + clock_sync[id].ftrace_params, clock_sync[id].events); + + if (clock_sync[id].clock_sync_init) + clock_sync[id].clock_sync_init(clock_context); + + clock_context->vinst = clock_synch_create_instance(clock_str, clock_context->remote_cid); + clock_context->tep = clock_synch_get_tep(clock_context->vinst, + clock_sync[id].systems); + i = 0; + while (clock_sync[id].events[i].name) { + event = tep_find_event_by_name(clock_context->tep, + clock_sync[id].events[i].system, + clock_sync[id].events[i].name); + if (!event) + break; + clock_context->events[i].id = event->id; + i++; + } +#ifdef TSYNC_DEBUG + clock_context->debug_fd = -1; +#endif + + return clock_context; + +} + +void tracecmd_clock_context_free(struct buffer_instance *instance) +{ + int i; + + if (instance->clock_sync == NULL || + instance->clock_sync->clock_context_id >= CLOCK_CONTEXT_MAX) + return; + if (clock_sync[instance->clock_sync->clock_context_id].clock_sync_free) + clock_sync[instance->clock_sync->clock_context_id].clock_sync_free(instance->clock_sync); + + i = 0; + while (instance->clock_sync->ftrace_params[i].file) { + free(instance->clock_sync->ftrace_params[i].file); + free(instance->clock_sync->ftrace_params[i].set); + free(instance->clock_sync->ftrace_params[i].reset); + i++; + } + free(instance->clock_sync->ftrace_params); + free(instance->clock_sync->events); + tracecmd_remove_instance(instance->clock_sync->vinst); + /* todo: clean up the instance */ + tep_free(instance->clock_sync->tep); + + free(instance->clock_sync->offsets); + free(instance->clock_sync->times); +#ifdef TSYNC_DEBUG + if (instance->clock_sync->debug_fd >= 0) { + close(instance->clock_sync->debug_fd); + instance->clock_sync->debug_fd = -1; + } +#endif + free(instance->clock_sync); + instance->clock_sync = NULL; +} + +bool tracecmd_time_sync_check(void) +{ +#ifdef VSOCK + return true; +#endif + return false; +} + +void sync_time_with_host_v3(struct buffer_instance *instance) +{ + long long timestamp = 0; + long long offset = 0; + + if (!instance->do_tsync) + return; + + if (instance->clock_sync == NULL) + instance->clock_sync = tracecmd_clock_context_new(instance->msg_handle, + instance->clock, CLOCK_KVM_X86_VSOCK_GUEST); + + tracecmd_msg_snd_time_sync(instance->msg_handle, instance->clock_sync, + &offset, ×tamp); + if (!offset && !timestamp) + warning("Failed to synchronize timestamps with the host"); +} + +void sync_time_with_guest_v3(struct buffer_instance *instance) +{ + long long timestamp = 0; + long long offset = 0; + long long *sync_array_ts; + long long *sync_array_offs; + + if (!instance->do_tsync) + return; + + if (instance->clock_sync == NULL) + instance->clock_sync = tracecmd_clock_context_new(instance->msg_handle, + top_instance.clock, CLOCK_KVM_X86_VSOCK_HOST); + + tracecmd_msg_rcv_time_sync(instance->msg_handle, + instance->clock_sync, &offset, ×tamp); + + if (!offset && !timestamp) { + warning("Failed to synchronize timestamps with guest %s", + instance->name); + return; + } + + sync_array_ts = realloc(instance->time_sync_ts, + (instance->time_sync_count+1)*sizeof(long long)); + sync_array_offs = realloc(instance->time_sync_offsets, + (instance->time_sync_count+1)*sizeof(long long)); + + if (sync_array_ts && sync_array_offs) { + sync_array_ts[instance->time_sync_count] = timestamp; + sync_array_offs[instance->time_sync_count] = offset; + instance->time_sync_count++; + instance->time_sync_ts = sync_array_ts; + instance->time_sync_offsets = sync_array_offs; + + } else { + free(sync_array_ts); + free(sync_array_offs); + } + +} + +static void set_clock_synch_events(struct buffer_instance *instance, + struct tracecmd_ftrace_param *params, + bool enable) +{ + int i = 0; + + if (!enable) + write_tracing_on(instance, 0); + + while (params[i].file) { + if (enable && params[i].set) { + write_instance_file(instance, params[i].file, + params[i].set, NULL); + } + if (!enable && params[i].reset) + write_instance_file(instance, params[i].file, + params[i].reset, NULL); + i++; + } + + if (enable) + write_tracing_on(instance, 1); +} + +int tracecmd_clock_get_peer(struct tracecmd_clock_sync *clock_context, + unsigned int *remote_cid, unsigned int *remote_port) +{ + if (!clock_context) + return 0; + if (remote_cid) + *remote_cid = clock_context->remote_cid; + if (remote_port) + *remote_cid = clock_context->remote_port; + return 1; +} + +void tracecmd_clock_synch_enable(struct tracecmd_clock_sync *clock_context) +{ + set_clock_synch_events(clock_context->vinst, + clock_context->ftrace_params, true); +} + +void tracecmd_clock_synch_disable(struct tracecmd_clock_sync *clock_context) +{ + set_clock_synch_events(clock_context->vinst, + clock_context->ftrace_params, false); +} + +int tracecmd_clock_synch_calc(struct tracecmd_clock_sync *clock_context, + long long *offset_ret, long long *time_ret) +{ + int i, j = 0; + long long av, tresch, offset = 0, time = 0; + + if (!clock_context || !clock_context->probes_count) + return 0; + av = clock_context->offset_av / clock_context->probes_count; + tresch = (long long)((clock_context->offset_max - clock_context->offset_min)/10); + + for (i = 0; i < clock_context->probes_count; i++) { + /* filter the offsets with deviation up to 10% */ + if (llabs(clock_context->offsets[i] - av) < tresch) { + offset += clock_context->offsets[i]; + j++; + } + } + if (j) + offset /= (long long)j; + + tresch = 0; + for (i = 0; i < clock_context->probes_count; i++) { + if ((!tresch || tresch > llabs(offset-clock_context->offsets[i]))) { + tresch = llabs(offset-clock_context->offsets[i]); + time = clock_context->times[i]; + } + } + if (offset_ret) + *offset_ret = offset; + if (time_ret) + *time_ret = time; +#ifdef TSYNC_DEBUG + printf("\n calculated offset: %lld, %d/%d probes\n\r", + *offset_ret, clock_context->probes_count, + clock_context->probes_count + clock_context->bad_probes); +#endif + return 1; +} + +void tracecmd_clock_synch_calc_reset(struct tracecmd_clock_sync *clock_context) +{ + if (!clock_context) + return; + + clock_context->probes_count = 0; + clock_context->bad_probes = 0; + clock_context->offset_av = 0; + clock_context->offset_min = 0; + clock_context->offset_max = 0; +#ifdef TSYNC_DEBUG + if (clock_context->debug_fd >= 0) { + close(clock_context->debug_fd); + clock_context->debug_fd = -1; + } +#endif + +} + +void tracecmd_clock_synch_calc_probe(struct tracecmd_clock_sync *clock_context, + long long ts_local, long long ts_remote) +{ + int count; +#ifdef TSYNC_DEBUG + char buff[256]; +#endif + + if (!clock_context || !ts_local || !ts_remote) + return; + if (!ts_local || !ts_remote) { + clock_context->bad_probes++; + return; + } + + if (!clock_context->offsets && !clock_context->times) { + clock_context->offsets = calloc(10, sizeof(long long)); + clock_context->times = calloc(10, sizeof(long long)); + clock_context->probes_size = 10; + } + + if (clock_context->probes_size == clock_context->probes_count) { + clock_context->probes_size = (3*clock_context->probes_size)/2; + clock_context->offsets = realloc(clock_context->offsets, + clock_context->probes_size * + sizeof(long long)); + clock_context->times = realloc(clock_context->times, + clock_context->probes_size* + sizeof(long long)); + } + + if (!clock_context->offsets || !clock_context->times) { + clock_context->probes_size = 0; + tracecmd_clock_synch_calc_reset(clock_context); + return; + } +#ifdef TSYNC_DEBUG + if (clock_context->debug_fd < 0) { + sprintf(buff, "s-cid%d.txt", clock_context->remote_cid); + clock_context->debug_fd = open(buff, O_CREAT|O_WRONLY|O_TRUNC, 0644); + } +#endif + count = clock_context->probes_count; + clock_context->probes_count++; + clock_context->offsets[count] = ts_remote - ts_local; + clock_context->times[count] = ts_local; + clock_context->offset_av += clock_context->offsets[count]; + + if (!clock_context->offset_min || + clock_context->offset_min > llabs(clock_context->offsets[count])) + clock_context->offset_min = llabs(clock_context->offsets[count]); + if (!clock_context->offset_max || + clock_context->offset_max < llabs(clock_context->offsets[count])) + clock_context->offset_max = llabs(clock_context->offsets[count]); +#ifdef TSYNC_DEBUG + sprintf(buff, "%lld %lld\n", ts_local, ts_remote); + write(clock_context->debug_fd, buff, strlen(buff)); +#endif + +}