From patchwork Thu Feb 27 14:19:47 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: "Tzvetomir Stoyanov (VMware)" X-Patchwork-Id: 11408679 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 C409B1805 for ; Thu, 27 Feb 2020 14:20:08 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.kernel.org (Postfix) with ESMTP id A308120801 for ; Thu, 27 Feb 2020 14:20:08 +0000 (UTC) Authentication-Results: mail.kernel.org; dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b="NcIBPNSh" Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S2389275AbgB0OUI (ORCPT ); Thu, 27 Feb 2020 09:20:08 -0500 Received: from mail-lf1-f68.google.com ([209.85.167.68]:39484 "EHLO mail-lf1-f68.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1730238AbgB0OUH (ORCPT ); Thu, 27 Feb 2020 09:20:07 -0500 Received: by mail-lf1-f68.google.com with SMTP id n30so2213320lfh.6 for ; Thu, 27 Feb 2020 06:20:06 -0800 (PST) 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=XXTKd2psy9mP8VEKnv7+0siRIXSAJcGRCU8ojoFidxY=; b=NcIBPNShofD5hJ73u/EWZSj3+d4VhqCpVgz2oAC1PyI/xDE8AXtBtPju/uhYqn2Ud3 gs76M2LRMrz2WlBRkLRXKYMSEzJ/KmWKldo6xD3rmGeaEBZzfDFvBleY2AEFI5kYhGvG 7iWV77DDth4awoyIKyT7Sh1cNxguQelviw44at8IYTqo1Ens5xxOAT21mxoMMTFJkQpH aO17Yuke+X9U3gYMyltd0m28zPL7U/C+0ZVrRsl21gBMu+2P+X0phIu4QWZpx7HWOHjm HN/VK6YJ9nypNC54Uo3I+mFoltNV7xABv7bIHNvJnUTHLRet7ytWIq34QRKkUEGZSojy kibA== 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=XXTKd2psy9mP8VEKnv7+0siRIXSAJcGRCU8ojoFidxY=; b=sLvIKi9ce2ufPiE9sFB1v3d9kZSySOPFVmJVfaW+W7JWiHGmZPv0Vm6ZtlXL2Es15a f4R5f/fmzUllfiLNFdSrSYH5d5fDtiinrLWqfs2vaGr7nmzpKD19S7VjMJwmOpesZHhz ycU3M6AfXqNEeZNKIfwYwe5KGQo6GSsOmaNzfQTuKUosrLJyNxfgP7Mf2ys/Np1jTHYG bAI441p0EUkpC5bYBx0N+pGtZGaIv+1p3X2+XeNvLXutRd75n6VpjBRJtQm1WuDXfmMk rOCTjKXZIbJGuxxtF0Oq7ih+3PmIhju1fnadFy+QQd/GZqsjhbcX9t8UgVrB4YzOrn/h 1jJA== X-Gm-Message-State: ANhLgQ3YFBTO3obKMcjS1XFy/XVmNEYbgpjF/92P/DZMKjspey/8LmgJ 5q/rbae01RUDkMg03grxKOU= X-Google-Smtp-Source: ADFU+vvd2S9JXaxm/fdR+qSipFL4HdvBnj9cRwiw5RJRPo8Nr9BnSpj2DXGcztXGz6pBz4vQYvwhJw== X-Received: by 2002:ac2:5c4d:: with SMTP id s13mr2426223lfp.128.1582813205703; Thu, 27 Feb 2020 06:20:05 -0800 (PST) Received: from oberon.zico.biz ([83.222.187.186]) by smtp.gmail.com with ESMTPSA id l3sm3306437lja.78.2020.02.27.06.20.04 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Thu, 27 Feb 2020 06:20:05 -0800 (PST) From: "Tzvetomir Stoyanov (VMware)" To: rostedt@goodmis.org Cc: linux-trace-devel@vger.kernel.org Subject: [PATCH v20 01/15] trace-cmd: Add support for negative time offsets in trace.dat file Date: Thu, 27 Feb 2020 16:19:47 +0200 Message-Id: <20200227142001.61577-2-tz.stoyanov@gmail.com> X-Mailer: git-send-email 2.24.1 In-Reply-To: <20200227142001.61577-1-tz.stoyanov@gmail.com> References: <20200227142001.61577-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 a243c250..6763715f 100644 --- a/include/trace-cmd/trace-cmd.h +++ b/include/trace-cmd/trace-cmd.h @@ -161,7 +161,7 @@ const char *tracecmd_buffer_instance_name(struct tracecmd_input *handle, int ind struct tracecmd_input *tracecmd_buffer_instance_handle(struct tracecmd_input *handle, int indx); int tracecmd_is_buffer_instance(struct tracecmd_input *handle); -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 a402f687..842a4c3b 100644 --- a/lib/trace-cmd/trace-input.c +++ b/lib/trace-cmd/trace-input.c @@ -93,7 +93,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; @@ -2036,7 +2036,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; } @@ -2215,7 +2215,7 @@ tracecmd_search_task_map(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 8c2b2ae3..c184c627 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; @@ -1466,7 +1466,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 Thu Feb 27 14:19:48 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: "Tzvetomir Stoyanov (VMware)" X-Patchwork-Id: 11408681 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 C81A792A for ; Thu, 27 Feb 2020 14:20:09 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.kernel.org (Postfix) with ESMTP id 9D4362468F for ; Thu, 27 Feb 2020 14:20:09 +0000 (UTC) Authentication-Results: mail.kernel.org; dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b="FZ5idwr7" Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S2389335AbgB0OUJ (ORCPT ); Thu, 27 Feb 2020 09:20:09 -0500 Received: from mail-lf1-f67.google.com ([209.85.167.67]:44045 "EHLO mail-lf1-f67.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S2389218AbgB0OUJ (ORCPT ); Thu, 27 Feb 2020 09:20:09 -0500 Received: by mail-lf1-f67.google.com with SMTP id 7so2186040lfz.11 for ; Thu, 27 Feb 2020 06:20:07 -0800 (PST) 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=w0c47qg0sT54NkrfJrWBkVp7ytwv30gVtL8LU5kRezM=; b=FZ5idwr7DoUunQWsKtf59LeIfoWTRvnKel3xIu+I8amDLDndEaDFNtCxmZHoJ/tUR5 XOOd+kDq4JZTu/3aVwFNU5zOcC3JTlBDV/XPYO2DydqqPrZ4KkYBaFjLG748Uq0XTgam w5m5Ug08jWueTO+5xdhdOwXB0N0wUfbVmHOPQNGV8IaH9W47WRzV9K3KmJEirjXb4/UO Rci+Pu5xVhRwBnKDfXqauAN1b7pzY2zESb2G927Wd9QHMsHDWXIDSUnvlLwOVkXPy3wP J1j0cIwCmgvzAFIAr+Z5lK5GwZ23DEt2mtuJrSZdgCNmUI7LuNLuYJqAm+Dkf7qVetB0 imGQ== 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=w0c47qg0sT54NkrfJrWBkVp7ytwv30gVtL8LU5kRezM=; b=SglkCr9Buj0vgbXiceMHAgYxEdDzP7Gc7HvuLmO0d0ljlDCW8HVGxEw+F1mYam99ck RFtT0GcfmOFkwYE2WCQMUe9RvBnh73Dx4Y+sXIAyqU0IQAXezTe77zFITQsa4h/6iAPw ZuSM6OG5OHajHamul4Wr6TRhbCaVMSRF4nC2c6AZpYZ0rnTsz9rTekCl3ACuIZ8SwLmQ j+OL1SgcgKWwhlHc3jKSYiQY9zhhr4ixY3/Ow4zPwDARMyYBTPS1UcCqE4rzDhGnm25Q Ihn0+jpNzdhX7fSE3K61vD/fMSarlUoLTZ2QvTlFXpdVAiLOIzq87VX9lrsFh3hO+r/3 HZyg== X-Gm-Message-State: ANhLgQ3xL+ZX8aQUrjSDstXQCh8PV8AtXsjCE726NzQvBCe/+iPuLcHp tm00oc3v/szA+bKxrxdvS6Y= X-Google-Smtp-Source: ADFU+vuewlaG8TMJ9F6qG9mmBBYvBiAmid30MRLnju01BVmRp1tWDjaGodS9bsU1YXGlRRLfMaXjTg== X-Received: by 2002:a05:6512:6f:: with SMTP id i15mr2279787lfo.45.1582813207072; Thu, 27 Feb 2020 06:20:07 -0800 (PST) Received: from oberon.zico.biz ([83.222.187.186]) by smtp.gmail.com with ESMTPSA id l3sm3306437lja.78.2020.02.27.06.20.05 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Thu, 27 Feb 2020 06:20:06 -0800 (PST) From: "Tzvetomir Stoyanov (VMware)" To: rostedt@goodmis.org Cc: linux-trace-devel@vger.kernel.org Subject: [PATCH v20 02/15] trace-cmd: Add new library API for local CPU count Date: Thu, 27 Feb 2020 16:19:48 +0200 Message-Id: <20200227142001.61577-3-tz.stoyanov@gmail.com> X-Mailer: git-send-email 2.24.1 In-Reply-To: <20200227142001.61577-1-tz.stoyanov@gmail.com> References: <20200227142001.61577-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 In order to reuse the code, the function detecting the number of local CPU is moved from trace-cmd application to libtracecmd. The following new library API is introduced: int tracecmd_count_cpus(void); Signed-off-by: Tzvetomir Stoyanov (VMware) --- include/trace-cmd/trace-cmd.h | 3 +++ lib/trace-cmd/trace-util.c | 49 ++++++++++++++++++++++++++++++++++ tracecmd/include/trace-local.h | 2 -- tracecmd/trace-agent.c | 2 +- tracecmd/trace-profile.c | 2 +- tracecmd/trace-record.c | 46 +++---------------------------- tracecmd/trace-stat.c | 4 +-- 7 files changed, 59 insertions(+), 49 deletions(-) diff --git a/include/trace-cmd/trace-cmd.h b/include/trace-cmd/trace-cmd.h index 6763715f..d1b4a60f 100644 --- a/include/trace-cmd/trace-cmd.h +++ b/include/trace-cmd/trace-cmd.h @@ -409,6 +409,9 @@ void tracecmd_plog(const char *fmt, ...); void tracecmd_plog_error(const char *fmt, ...); int tracecmd_set_logfile(char *logfile); +/* --- System --- */ +int tracecmd_count_cpus(void); + /* --- Hack! --- */ int tracecmd_blk_hack(struct tracecmd_input *handle); diff --git a/lib/trace-cmd/trace-util.c b/lib/trace-cmd/trace-util.c index fc2bcb24..b8841393 100644 --- a/lib/trace-cmd/trace-util.c +++ b/lib/trace-cmd/trace-util.c @@ -461,3 +461,52 @@ int tracecmd_stack_tracer_status(int *status) *status = num; return 1; /* full success */ } + +/** + * tracecmd_count_cpus - Get the number of CPUs in the system + * + * Returns the number of CPUs in the system, or 0 in case of an error + */ +int tracecmd_count_cpus(void) +{ + static int once; + char buf[1024]; + int cpus = 0; + char *pbuf; + size_t *pn; + FILE *fp; + size_t n; + int r; + + cpus = sysconf(_SC_NPROCESSORS_CONF); + if (cpus > 0) + return cpus; + + if (!once) { + once++; + warning("sysconf could not determine number of CPUS"); + } + + /* Do the hack to figure out # of CPUS */ + n = 1024; + pn = &n; + pbuf = buf; + + fp = fopen("/proc/cpuinfo", "r"); + if (!fp) + die("Can not read cpuinfo"); + + while ((r = getline(&pbuf, pn, fp)) >= 0) { + char *p; + + if (strncmp(buf, "processor", 9) != 0) + continue; + for (p = buf+9; isspace(*p); p++) + ; + if (*p == ':') + cpus++; + } + fclose(fp); + + return cpus; +} diff --git a/tracecmd/include/trace-local.h b/tracecmd/include/trace-local.h index 7a0804e2..29f27793 100644 --- a/tracecmd/include/trace-local.h +++ b/tracecmd/include/trace-local.h @@ -247,8 +247,6 @@ 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); - /* moved from trace-cmd.h */ void tracecmd_create_top_instance(char *name); void tracecmd_remove_instances(void); diff --git a/tracecmd/trace-agent.c b/tracecmd/trace-agent.c index 93e3edfd..1c6e0a3a 100644 --- a/tracecmd/trace-agent.c +++ b/tracecmd/trace-agent.c @@ -203,7 +203,7 @@ static void agent_serve(unsigned int port) signal(SIGCHLD, handle_sigchld); - nr_cpus = count_cpus(); + nr_cpus = tracecmd_count_cpus(); page_size = getpagesize(); sd = make_vsock(port); diff --git a/tracecmd/trace-profile.c b/tracecmd/trace-profile.c index 231e3816..cfae2a22 100644 --- a/tracecmd/trace-profile.c +++ b/tracecmd/trace-profile.c @@ -1314,7 +1314,7 @@ void trace_init_profile(struct tracecmd_input *handle, struct hook_list *hook, * system. */ if (!h->cpus) - h->cpus = count_cpus(); + h->cpus = tracecmd_count_cpus(); list_head_init(&h->migrate_starts); h->cpu_starts = malloc(sizeof(*h->cpu_starts) * h->cpus); diff --git a/tracecmd/trace-record.c b/tracecmd/trace-record.c index 4a49b640..28fe31b7 100644 --- a/tracecmd/trace-record.c +++ b/tracecmd/trace-record.c @@ -2884,46 +2884,6 @@ static void expand_event_list(void) expand_event_instance(instance); } -int count_cpus(void) -{ - FILE *fp; - char buf[1024]; - int cpus = 0; - char *pbuf; - size_t *pn; - size_t n; - int r; - - cpus = sysconf(_SC_NPROCESSORS_CONF); - if (cpus > 0) - return cpus; - - warning("sysconf could not determine number of CPUS"); - - /* Do the hack to figure out # of CPUS */ - n = 1024; - pn = &n; - pbuf = buf; - - fp = fopen("/proc/cpuinfo", "r"); - if (!fp) - die("Can not read cpuinfo"); - - while ((r = getline(&pbuf, pn, fp)) >= 0) { - char *p; - - if (strncmp(buf, "processor", 9) != 0) - continue; - for (p = buf+9; isspace(*p); p++) - ; - if (*p == ':') - cpus++; - } - fclose(fp); - - return cpus; -} - static void finish(int sig) { /* all done */ @@ -4608,7 +4568,7 @@ static void reset_clock(void) static void reset_cpu_mask(void) { struct buffer_instance *instance; - int cpus = count_cpus(); + int cpus = tracecmd_count_cpus(); int fullwords = (cpus - 1) / 32; int bits = (cpus - 1) % 32 + 1; int len = (fullwords + 1) * 9; @@ -5165,7 +5125,7 @@ void init_top_instance(void) { if (!top_instance.tracefs) top_instance.tracefs = tracefs_instance_alloc(NULL); - top_instance.cpu_count = count_cpus(); + top_instance.cpu_count = tracecmd_count_cpus(); top_instance.flags = BUFFER_FL_KEEP; init_instance(&top_instance); } @@ -5362,7 +5322,7 @@ 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; - local_cpu_count = count_cpus(); + local_cpu_count = tracecmd_count_cpus(); init_top_instance(); } diff --git a/tracecmd/trace-stat.c b/tracecmd/trace-stat.c index 0db3baca..3a086a69 100644 --- a/tracecmd/trace-stat.c +++ b/tracecmd/trace-stat.c @@ -738,7 +738,7 @@ static void report_cpumask(struct buffer_instance *instance) cont = strstrip(str); /* check to make sure all CPUs on this machine are set */ - cpus = count_cpus(); + cpus = tracecmd_count_cpus(); for (i = strlen(cont) - 1; i >= 0 && cpus > 0; i--) { if (cont[i] == ',') @@ -898,7 +898,7 @@ void trace_stat (int argc, char **argv) instance = create_instance(optarg); if (!instance) die("Failed to create instance"); - add_instance(instance, count_cpus()); + add_instance(instance, tracecmd_count_cpus()); /* top instance requires direct access */ if (!topt && is_top_instance(first_instance)) first_instance = instance; From patchwork Thu Feb 27 14:19:49 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: "Tzvetomir Stoyanov (VMware)" X-Patchwork-Id: 11408685 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 DA98D930 for ; Thu, 27 Feb 2020 14:20:14 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.kernel.org (Postfix) with ESMTP id B960C246B1 for ; Thu, 27 Feb 2020 14:20:14 +0000 (UTC) Authentication-Results: mail.kernel.org; dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b="uQwBJ9pp" Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1730238AbgB0OUO (ORCPT ); Thu, 27 Feb 2020 09:20:14 -0500 Received: from mail-lj1-f193.google.com ([209.85.208.193]:42069 "EHLO mail-lj1-f193.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S2389286AbgB0OUK (ORCPT ); Thu, 27 Feb 2020 09:20:10 -0500 Received: by mail-lj1-f193.google.com with SMTP id d10so3594407ljl.9 for ; Thu, 27 Feb 2020 06:20:09 -0800 (PST) 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=yiF6QtTYqc6joapxz43L77Kv6esYCIHA1NtahqXpj5c=; b=uQwBJ9ppMU2qlXp5UWyYUiABJpeprj4A8hMPF3IrhEe9q99uA5bFTnX8CcrWRnBlVE u6/WAeccqCisKFEjK4fH5Z8H/IeDZ18wWoYCFjLS9uMnwKTmZjq8puyMbEBxCVpCaykC 52YMDB8gx9Yf/NzE/fig8HHtCqR4mjObRwq+WBsFZBoAysTWnshY/0/JRLBmyUxNaNQr xPzYnxKnQIAHc4iHtj5fgJwQ7NsUcpL64V4f320YJ5lMtgcd8NJ8CDVSO7Vpbhvx4WVL BN+m8wpF2ch2W5UeQ5eKx+EbxkKkWmEHQW3saOTFcgGbWpN+c6wvQYvCGbD2Ema41yvp pzwg== 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=yiF6QtTYqc6joapxz43L77Kv6esYCIHA1NtahqXpj5c=; b=TQbhlcWSY3CCA5kWp/NV6/vvRSjwJMeo4k2jCZBpQa1gjXdTEok3PUkmOljwrPqHea dCSNx2FQEROj8q47HXg2Lvaik2y5lMoKsiYSulMAeY2laxK3h/rLd2rgtLQGCL5lxrfe o563JPB69F22QlgNi+T3oEEuJGMxKfBAmUMXHmTkbPEd9FKBNBf5rOdWtDG61OlQ/p/D Ap1y3o2VAoKHg31KKgwIABQ/On23HhvLOJzq04Mgtbg506c6GqG0yAMQtmgTtO0vSzjD ZqnEjwWhXQI8+Q9jCfryhyIQnko87bItOd2IQs22H/GYpz3lZfNxqcwKIjXwuzdOGIAo 85zQ== X-Gm-Message-State: ANhLgQ0kExz4qVkhgFPCw42UQsFbHw/ydsOn54tnMFknNNBdKTCbKQVr WRFLPcfpRK4tCbCDGG3Py3wTOIBXxlU= X-Google-Smtp-Source: ADFU+vshd2DCLxc3QIU60l2hb6lX/J54gBxS53Z/HsYBIe9PdKoKLd8/N8Fv0sgi4VZ0+0nQ1mOVdA== X-Received: by 2002:a2e:9748:: with SMTP id f8mr3213392ljj.178.1582813208499; Thu, 27 Feb 2020 06:20:08 -0800 (PST) Received: from oberon.zico.biz ([83.222.187.186]) by smtp.gmail.com with ESMTPSA id l3sm3306437lja.78.2020.02.27.06.20.07 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Thu, 27 Feb 2020 06:20:07 -0800 (PST) From: "Tzvetomir Stoyanov (VMware)" To: rostedt@goodmis.org Cc: linux-trace-devel@vger.kernel.org Subject: [PATCH v20 03/15] trace-cmd: Find and store pids of tasks, which run virtual CPUs of given VM Date: Thu, 27 Feb 2020 16:19:49 +0200 Message-Id: <20200227142001.61577-4-tz.stoyanov@gmail.com> X-Mailer: git-send-email 2.24.1 In-Reply-To: <20200227142001.61577-1-tz.stoyanov@gmail.com> References: <20200227142001.61577-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 | 2 + tracecmd/trace-record.c | 77 ++++++++++++++++++++++++++++++++++ 2 files changed, 79 insertions(+) diff --git a/tracecmd/include/trace-local.h b/tracecmd/include/trace-local.h index 29f27793..a5cf0640 100644 --- a/tracecmd/include/trace-local.h +++ b/tracecmd/include/trace-local.h @@ -247,6 +247,8 @@ void update_first_instance(struct buffer_instance *instance, int topt); void show_instance_file(struct buffer_instance *instance, const char *name); +int get_guest_vcpu_pid(unsigned int guest_cid, unsigned int guest_vcpu); + /* moved from trace-cmd.h */ void tracecmd_create_top_instance(char *name); void tracecmd_remove_instances(void); diff --git a/tracecmd/trace-record.c b/tracecmd/trace-record.c index 28fe31b7..4370c964 100644 --- a/tracecmd/trace-record.c +++ b/tracecmd/trace-record.c @@ -3035,11 +3035,30 @@ struct guest { char *name; int cid; int pid; + int cpu_max; + int *cpu_pid; }; static struct guest *guests; static size_t guests_len; +static int set_vcpu_pid_mapping(struct guest *guest, int cpu, int pid) +{ + int *cpu_pid; + + if (cpu < 0 || pid < 0) + return -1; + if (cpu >= guest->cpu_max) { + cpu_pid = realloc(guest->cpu_pid, (cpu + 1) * sizeof(int)); + if (!cpu_pid) + return -1; + guest->cpu_max = cpu + 1; + guest->cpu_pid = cpu_pid; + } + guest->cpu_pid[cpu] = pid; + return 0; +} + static char *get_qemu_guest_name(char *arg) { char *tok, *end = arg; @@ -3052,6 +3071,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; + long int vcpu; + long int pid; + 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 && + strncmp(buf, "CPU ", 4) == 0) { + vcpu = strtol(buf + 4, NULL, 10); + pid = strtol(entry->d_name, NULL, 10); + if (vcpu < INT_MAX && pid < INT_MAX && + vcpu >= 0 && pid >= 0) + set_vcpu_pid_mapping(guest, vcpu, pid); + } + + fclose(f); + } + free(buf); +} + static void read_qemu_guests(void) { static bool initialized; @@ -3115,6 +3174,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"); @@ -3160,6 +3221,22 @@ 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) + return -1; + + for (i = 0; i < guests_len; i++) { + if (!guests[i].cpu_pid || guest_vcpu >= guests[i].cpu_max) + continue; + 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 Thu Feb 27 14:19:50 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: "Tzvetomir Stoyanov (VMware)" X-Patchwork-Id: 11408683 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 AC87F92A for ; Thu, 27 Feb 2020 14:20:14 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.kernel.org (Postfix) with ESMTP id 837AC246B1 for ; Thu, 27 Feb 2020 14:20:14 +0000 (UTC) Authentication-Results: mail.kernel.org; dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b="jfX52asg" Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S2389830AbgB0OUN (ORCPT ); Thu, 27 Feb 2020 09:20:13 -0500 Received: from mail-lj1-f195.google.com ([209.85.208.195]:42072 "EHLO mail-lj1-f195.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1730238AbgB0OUM (ORCPT ); Thu, 27 Feb 2020 09:20:12 -0500 Received: by mail-lj1-f195.google.com with SMTP id d10so3594495ljl.9 for ; Thu, 27 Feb 2020 06:20:10 -0800 (PST) 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=HT/OFwCq9NMeexvwL+8+0hJRAzEV1ED9p/K4+kIVNa4=; b=jfX52asg2Fmp4BEtFu8zJUPFIIvN1tsM9NTuTqX8K8gvHj0oF1D8wV1vKdbG7qnq+0 6kYfDpBjwNRQFV0GpFEKDGKxZp/8Xe6YbX4cHdjKo+U2vKR9T71sS/3GXVLN/YxD3Z7o mEMkfL+v056D8F362YJjQjlGkT7+Twzga/WkytPrrDoeHLR7uPQT/WQr4JcM0kQbHrzj sVDmmJ/5mSm6kJJrb4WDrFEWAckEpMon+RI0eU9rb/RmNqAeqF+VBpiCWQETJ7y6RQgx vu2sCJ6X6+AXgPT09vtPQwUm+vIU1yjF3g9h6fQBLf2lxrNHGeVjVrbmz/3q3FYN4/L3 amOA== 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=HT/OFwCq9NMeexvwL+8+0hJRAzEV1ED9p/K4+kIVNa4=; b=asGuNDI/7wM3ObCU3V5ZZ0UzREFWVjlAZgYqPXSRptIbs0rBjKrM0k9FxJSnRQd02V +kXbNZpt9ehd/wfnNpB3sZR3zp42BttWF7rd30hfoAphteb5I/H+mCREVoepq+EAr4a2 C8FkPnmvUIdYms0ElLLwkzwvtSpD3GEs5WTNtV73r9SAmHXqdPtYMGCa7rIT0e74/lgl pOO2oe7mfCsa93YgcwWhTfWkO3OVt6lBFmZeY2iKLzQDM2pR1TPbdsxDwGRS559KOfKO jnA9+8FVyMBR6OG8ZsILtbrGWCRLbavsZaRX8jGuUvD8rNE2rr6PuNi9kdbySfvaCqT8 VwaA== X-Gm-Message-State: ANhLgQ2MoBhhILVJMBQFhIk+ztQdorvLHJibKaAJGAZwBoiqNYGiJ4lr v/R0c2uRUh4AbX19I5TV39pb7aamEhk= X-Google-Smtp-Source: ADFU+vsmq+YNNs/AQ7RSRqx1Gjpra3+4JHGFK+7giKEC5H7m8QiSff8xOH0yIqqeiGDuQWW01WtczQ== X-Received: by 2002:a2e:3619:: with SMTP id d25mr2965264lja.231.1582813209903; Thu, 27 Feb 2020 06:20:09 -0800 (PST) Received: from oberon.zico.biz ([83.222.187.186]) by smtp.gmail.com with ESMTPSA id l3sm3306437lja.78.2020.02.27.06.20.08 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Thu, 27 Feb 2020 06:20:09 -0800 (PST) From: "Tzvetomir Stoyanov (VMware)" To: rostedt@goodmis.org Cc: linux-trace-devel@vger.kernel.org Subject: [PATCH v20 04/15] trace-cmd: Implement new API tracecmd_add_option_v() Date: Thu, 27 Feb 2020 16:19:50 +0200 Message-Id: <20200227142001.61577-5-tz.stoyanov@gmail.com> X-Mailer: git-send-email 2.24.1 In-Reply-To: <20200227142001.61577-1-tz.stoyanov@gmail.com> References: <20200227142001.61577-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 A new tracecmd API tracecmd_add_option_v() is introduced. 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 + lib/trace-cmd/trace-output.c | 117 +++++++++++++++++++++++++++---- 3 files changed, 108 insertions(+), 15 deletions(-) diff --git a/include/trace-cmd/trace-cmd.h b/include/trace-cmd/trace-cmd.h index d1b4a60f..b6393a89 100644 --- a/include/trace-cmd/trace-cmd.h +++ b/include/trace-cmd/trace-cmd.h @@ -278,11 +278,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 52bafa54..cfab6005 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/lib/trace-cmd/trace-output.c b/lib/trace-cmd/trace-output.c index a3dda270..acdd2d57 100644 --- a/lib/trace-cmd/trace-output.c +++ b/lib/trace-cmd/trace-output.c @@ -951,21 +951,27 @@ 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. + * @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. @@ -974,32 +980,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); @@ -1047,6 +1084,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 Thu Feb 27 14:19:51 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: "Tzvetomir Stoyanov (VMware)" X-Patchwork-Id: 11408695 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 B36FF18E8 for ; Thu, 27 Feb 2020 14:20:21 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.kernel.org (Postfix) with ESMTP id 9273220801 for ; Thu, 27 Feb 2020 14:20:21 +0000 (UTC) Authentication-Results: mail.kernel.org; dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b="Rwn2IvLb" Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S2389853AbgB0OUO (ORCPT ); Thu, 27 Feb 2020 09:20:14 -0500 Received: from mail-lj1-f196.google.com ([209.85.208.196]:39105 "EHLO mail-lj1-f196.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S2389385AbgB0OUN (ORCPT ); Thu, 27 Feb 2020 09:20:13 -0500 Received: by mail-lj1-f196.google.com with SMTP id o15so3614536ljg.6 for ; Thu, 27 Feb 2020 06:20:12 -0800 (PST) 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=fEiEQ65BuT5IqZCKZwhrCwsHR9aSt/uIprrHvPKzN7I=; b=Rwn2IvLbzFe0vvcMC/Afg2gM94n1Z0zH82GIJ2ZDjgLm6IsOkY2lUiD/v/xCMf63Fc bUtW9rhXb7bBE1/VjbmwHPRvYCMIWNPMwjPn9eUpEy5D0MEVv+FzA7txkbOMCxJ5ytfR VyUxLOXRgERHLMh5CwQ5VeLpQRpoqxh3Y18EdhlzOAAenCQ+HegXbC8v+LvFmIXqR0nZ Rg6qZ49PPonWeHWcmLuerxQ3SSO25N/SMW+WNIQP5NhAQSBP1DYCjxjW6izR+Z5LTDhU e3iqtBrAgKnO+zS2K14VqrW/XnKkJpZrzsaaD3N5TFIffok7jxCTN6gneDgB2sM8pUSX ENwQ== 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=fEiEQ65BuT5IqZCKZwhrCwsHR9aSt/uIprrHvPKzN7I=; b=ejr8rA3BcSZFgo7VqUbM/RqIf70krvYavNB7h02vGnBp2wCq7fnDYL6Lg3/Vj/70DP O719ZHdyZzSF66iw3sDmZvBULZO+xRb709e+qiAUGJyWpn9uec6ZfHVRMq0vmTeFn3Jl cFKl1HcvILFvEplChQNxcugreu0sqVCr/p0yRVr/Linq5eV80B/xlQgTq3mUukN6NFyl rVZWuAulqPbDXG0tjvTm65OdydEFt86bMH8MUDkPPFKoDGeks+iU73ATkewk6UvbyGTW L2lgMUET7uYzUUINxIy9OAtfxlKrOU7dpG5Ujv5AXgi8ecNHuuh8ipx4hV26mG2T2puS FTtg== X-Gm-Message-State: ANhLgQ1mVaCKuEZzz3O28D+VeEixuS/ftyGg8QZlL3xKz1lMSqOodktn ttlAibhvQlCkt4+PaNf7N9E= X-Google-Smtp-Source: ADFU+vtJz+krLXXsi3PWJKpvYcYiR3U73tzG1gkvZ22n+5tiAwaU1YfcdfdSXKzTG3wyMAzZQgwY6A== X-Received: by 2002:a05:651c:327:: with SMTP id b7mr2823085ljp.22.1582813211207; Thu, 27 Feb 2020 06:20:11 -0800 (PST) Received: from oberon.zico.biz ([83.222.187.186]) by smtp.gmail.com with ESMTPSA id l3sm3306437lja.78.2020.02.27.06.20.10 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Thu, 27 Feb 2020 06:20:10 -0800 (PST) From: "Tzvetomir Stoyanov (VMware)" To: rostedt@goodmis.org Cc: linux-trace-devel@vger.kernel.org Subject: [PATCH v20 05/15] trace-cmd: Add new API to generate a unique ID of the tracing session Date: Thu, 27 Feb 2020 16:19:51 +0200 Message-Id: <20200227142001.61577-6-tz.stoyanov@gmail.com> X-Mailer: git-send-email 2.24.1 In-Reply-To: <20200227142001.61577-1-tz.stoyanov@gmail.com> References: <20200227142001.61577-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 A new libtracecmd API is implemented: unsigned long long tracecmd_generate_traceid(void); At trace-cmd init phase a unique ID, used for the current tracing session. Signed-off-by: Tzvetomir Stoyanov (VMware) --- include/trace-cmd/trace-cmd.h | 1 + lib/trace-cmd/trace-util.c | 37 ++++++++++++++++++++++++++++++++++ tracecmd/include/trace-local.h | 1 + tracecmd/trace-record.c | 1 + 4 files changed, 40 insertions(+) diff --git a/include/trace-cmd/trace-cmd.h b/include/trace-cmd/trace-cmd.h index b6393a89..7519e82a 100644 --- a/include/trace-cmd/trace-cmd.h +++ b/include/trace-cmd/trace-cmd.h @@ -415,6 +415,7 @@ void tracecmd_plog_error(const char *fmt, ...); int tracecmd_set_logfile(char *logfile); /* --- System --- */ +unsigned long long tracecmd_generate_traceid(void); int tracecmd_count_cpus(void); /* --- Hack! --- */ diff --git a/lib/trace-cmd/trace-util.c b/lib/trace-cmd/trace-util.c index b8841393..04dc804c 100644 --- a/lib/trace-cmd/trace-util.c +++ b/lib/trace-cmd/trace-util.c @@ -18,6 +18,8 @@ #include #include #include +#include +#include #include "trace-cmd.h" #include "event-utils.h" @@ -510,3 +512,38 @@ int tracecmd_count_cpus(void) return cpus; } + +#define FNV_64_PRIME 0x100000001b3ULL +/* + * tracecmd_generate_traceid - Generate a unique ID, used to identify + * the current tracing session + * + * Returns unique ID + */ +unsigned long long tracecmd_generate_traceid(void) +{ + unsigned long long hash = 0; + unsigned char *ustr; + struct sysinfo sinfo; + struct timespec ts; + char *str = NULL; + + clock_gettime(CLOCK_MONOTONIC_RAW, &ts); + sysinfo(&sinfo); + asprintf(&str, "%ld %ld %ld %ld %ld %ld %ld %ld %d", + ts.tv_sec, ts.tv_nsec, + sinfo.loads[0], sinfo.loads[1], sinfo.loads[2], + sinfo.freeram, sinfo.sharedram, sinfo.freeswap, + sinfo.procs); + if (!str) + return 0; + ustr = (unsigned char *)str; + hash = 0; + while (*ustr) { + hash ^= (unsigned long long)*ustr++; + hash *= FNV_64_PRIME; + } + + free(str); + return hash; +} diff --git a/tracecmd/include/trace-local.h b/tracecmd/include/trace-local.h index a5cf0640..6fe22bb0 100644 --- a/tracecmd/include/trace-local.h +++ b/tracecmd/include/trace-local.h @@ -185,6 +185,7 @@ struct pid_addr_maps { struct buffer_instance { struct buffer_instance *next; struct tracefs_instance *tracefs; + unsigned long long trace_id; char *cpumask; struct event_list *events; struct event_list **event_next; diff --git a/tracecmd/trace-record.c b/tracecmd/trace-record.c index 4370c964..5d31cad8 100644 --- a/tracecmd/trace-record.c +++ b/tracecmd/trace-record.c @@ -5204,6 +5204,7 @@ void init_top_instance(void) top_instance.tracefs = tracefs_instance_alloc(NULL); top_instance.cpu_count = tracecmd_count_cpus(); top_instance.flags = BUFFER_FL_KEEP; + top_instance.trace_id = tracecmd_generate_traceid(); init_instance(&top_instance); } From patchwork Thu Feb 27 14:19:52 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: "Tzvetomir Stoyanov (VMware)" X-Patchwork-Id: 11408697 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 DDDBB1871 for ; Thu, 27 Feb 2020 14:20:21 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.kernel.org (Postfix) with ESMTP id BC84220801 for ; Thu, 27 Feb 2020 14:20:21 +0000 (UTC) Authentication-Results: mail.kernel.org; dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b="E+/tB3QH" Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S2389750AbgB0OUV (ORCPT ); Thu, 27 Feb 2020 09:20:21 -0500 Received: from mail-lj1-f194.google.com ([209.85.208.194]:40077 "EHLO mail-lj1-f194.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S2389828AbgB0OUP (ORCPT ); Thu, 27 Feb 2020 09:20:15 -0500 Received: by mail-lj1-f194.google.com with SMTP id 143so3490219ljj.7 for ; Thu, 27 Feb 2020 06:20:13 -0800 (PST) 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=MVPIveRg6oAAd84/z9Xl82WSwrk+YDdhl6fFI3ImcsY=; b=E+/tB3QH5yyVv8Zlq/pZfiluSdBgZ67oYhsFfHMVKcbl9oNYdQNMsgtoNeF761XCx/ ypOXZQALp+lX3hmuns1rak18sEVXTCromOSExxcyqtczel06Zb1x8WgWjBWevqoVet5l hcc3DbH7TLXlJgM8K+4XGlap6fBDaU+I936tynKx9ctdtNgiwpkYqhUhQ/UBQDXZiN4K W6El+NwqFpOgg+xUgPEDndNhBLggjk0zSngoiGL8mh8Kf//5ezkkytobukOb7BZJxdOG DPGfFMJRQTS0Z9hsZ1u5dleVLnkdIDBilkrLWv0AWVbqbKf/8JHV7212DxBJpa55i+J7 Xy8A== 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=MVPIveRg6oAAd84/z9Xl82WSwrk+YDdhl6fFI3ImcsY=; b=X09a6OgSxQJ3HblyzWBueN4cFQyiR+QrKQV/SR1m0qQx9yyBdNowWN0H466XJ+9P4z UHmtRwV3a0UAYNF7Mnor0OwllaFqEIh2V0gsQ4HK7CZL85jk2Us+rkf0h0qe2Sgt8x2H wQiBbsCRsfqmnKKXujR3fC5HDY0ViKpetLtUvj9O3OS+lYgMTQ2/3gkomuBlmUFRWaua DiWOcsEjD4/rdg2Q7dxm09wl91d5VSTPUeaqvZyTLyWGW9biowCR5dY97xSmUhAgl1y6 ZkZG0P7rjUdAK5h+AwUyWV7psxuuPcqMK8+Mj+VDG7FVVqhhimW57p+mfnHw17/+9898 iA0w== X-Gm-Message-State: ANhLgQ08Dk0V27QFEg340jODXw9s0mtnIiPwHE+2Y2sL4KeX0SkM8gcq 7+C+8jQvwBNmFIkuhAiS34E= X-Google-Smtp-Source: ADFU+vsfYR2psKFHQXQkxSG9sYjBgR/OXX3B4GHR9gfnAxZ4e3GLFMGwaFKgLsZWkA1fvO06QOSEYA== X-Received: by 2002:a2e:9708:: with SMTP id r8mr3009811lji.92.1582813212363; Thu, 27 Feb 2020 06:20:12 -0800 (PST) Received: from oberon.zico.biz ([83.222.187.186]) by smtp.gmail.com with ESMTPSA id l3sm3306437lja.78.2020.02.27.06.20.11 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Thu, 27 Feb 2020 06:20:11 -0800 (PST) From: "Tzvetomir Stoyanov (VMware)" To: rostedt@goodmis.org Cc: linux-trace-devel@vger.kernel.org Subject: [PATCH v20 06/15] trace-cmd: Store the session tracing ID in the trace.dat file Date: Thu, 27 Feb 2020 16:19:52 +0200 Message-Id: <20200227142001.61577-7-tz.stoyanov@gmail.com> X-Mailer: git-send-email 2.24.1 In-Reply-To: <20200227142001.61577-1-tz.stoyanov@gmail.com> References: <20200227142001.61577-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 The ID of the current tracing session is stored in the trace.dat file. A new file option is introduced: TRACECMD_OPTION_TRACEID The data is stored in the file as unsigned long long integer A new libtracecmd API is introduced, to get the ID when the trace.dat file is read: unsigned long long tracecmd_get_traceid(struct tracecmd_input *handle); Signed-off-by: Tzvetomir Stoyanov (VMware) --- include/trace-cmd/trace-cmd.h | 2 ++ lib/trace-cmd/trace-input.c | 16 ++++++++++++++++ tracecmd/trace-dump.c | 11 +++++++++++ tracecmd/trace-record.c | 9 +++++++++ 4 files changed, 38 insertions(+) diff --git a/include/trace-cmd/trace-cmd.h b/include/trace-cmd/trace-cmd.h index 7519e82a..6075a37e 100644 --- a/include/trace-cmd/trace-cmd.h +++ b/include/trace-cmd/trace-cmd.h @@ -109,6 +109,7 @@ enum { TRACECMD_OPTION_CPUCOUNT, TRACECMD_OPTION_VERSION, TRACECMD_OPTION_PROCMAPS, + TRACECMD_OPTION_TRACEID, }; enum { @@ -151,6 +152,7 @@ int tracecmd_copy_headers(struct tracecmd_input *handle, int fd); void tracecmd_set_flag(struct tracecmd_input *handle, int flag); void tracecmd_clear_flag(struct tracecmd_input *handle, int flag); unsigned long tracecmd_get_flags(struct tracecmd_input *handle); +unsigned long long tracecmd_get_traceid(struct tracecmd_input *handle); void tracecmd_parse_trace_clock(struct tracecmd_input *handle, char *file, int size); diff --git a/lib/trace-cmd/trace-input.c b/lib/trace-cmd/trace-input.c index 842a4c3b..aca13c4e 100644 --- a/lib/trace-cmd/trace-input.c +++ b/lib/trace-cmd/trace-input.c @@ -82,6 +82,7 @@ struct tracecmd_input { struct tep_plugin_list *plugin_list; struct tracecmd_input *parent; unsigned long flags; + unsigned long long trace_id; int fd; int long_size; int page_size; @@ -2316,6 +2317,10 @@ static int handle_options(struct tracecmd_input *handle) if (buf[size-1] == '\0') trace_pid_map_load(handle, buf); break; + case TRACECMD_OPTION_TRACEID: + handle->trace_id = tep_read_number(handle->pevent, + &cpus, 8); + break; default: warning("unknown option %d", option); break; @@ -3419,3 +3424,14 @@ void tracecmd_set_show_data_func(struct tracecmd_input *handle, { handle->show_data_func = func; } + +/** + * tracecmd_get_traceid - get the trace id of the session + * @handle: input handle for the trace.dat file + * + * Returns the trace id, written in the trace file + */ +unsigned long long tracecmd_get_traceid(struct tracecmd_input *handle) +{ + return handle->trace_id; +} diff --git a/tracecmd/trace-dump.c b/tracecmd/trace-dump.c index 415e9138..2dfeaa0f 100644 --- a/tracecmd/trace-dump.c +++ b/tracecmd/trace-dump.c @@ -358,6 +358,14 @@ static void dump_option_int(int fd, int size, char *desc) do_print(OPTIONS, "%d\n", val); } +static void dump_option_xlong(int fd, int size, char *desc) +{ + long long val; + + do_print(OPTIONS, "\t\t[Option %s, %d bytes]\n", desc, size); + read_file_number(fd, &val, size); + do_print(OPTIONS, "0x%llX\n", val); +} static void dump_options(int fd) { unsigned short option; @@ -408,6 +416,9 @@ static void dump_options(int fd) case TRACECMD_OPTION_PROCMAPS: dump_option_string(fd, size, "PROCMAPS"); break; + case TRACECMD_OPTION_TRACEID: + dump_option_xlong(fd, size, "TRACEID"); + break; default: do_print(OPTIONS, " %d %d\t[Unknown option, size - skipping]\n", option, size); diff --git a/tracecmd/trace-record.c b/tracecmd/trace-record.c index 5d31cad8..3e24eb43 100644 --- a/tracecmd/trace-record.c +++ b/tracecmd/trace-record.c @@ -3895,6 +3895,13 @@ add_pid_maps(struct tracecmd_output *handle, struct buffer_instance *instance) trace_seq_destroy(&s); } +static void +add_trace_id(struct tracecmd_output *handle, struct buffer_instance *instance) +{ + tracecmd_add_option(handle, TRACECMD_OPTION_TRACEID, + sizeof(long long), &instance->trace_id); +} + static void add_buffer_stat(struct tracecmd_output *handle, struct buffer_instance *instance) { @@ -4000,6 +4007,8 @@ static void add_options(struct tracecmd_output *handle, struct common_record_con add_option_hooks(handle); add_uname(handle); add_version(handle); + if (!no_top_instance()) + add_trace_id(handle, &top_instance); } static void write_guest_file(struct buffer_instance *instance) From patchwork Thu Feb 27 14:19:53 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: "Tzvetomir Stoyanov (VMware)" X-Patchwork-Id: 11408687 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 25535930 for ; Thu, 27 Feb 2020 14:20:18 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.kernel.org (Postfix) with ESMTP id 045D52468F for ; Thu, 27 Feb 2020 14:20:17 +0000 (UTC) Authentication-Results: mail.kernel.org; dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b="GMlNI+2W" Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S2389875AbgB0OUQ (ORCPT ); Thu, 27 Feb 2020 09:20:16 -0500 Received: from mail-lj1-f193.google.com ([209.85.208.193]:41599 "EHLO mail-lj1-f193.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S2389286AbgB0OUQ (ORCPT ); Thu, 27 Feb 2020 09:20:16 -0500 Received: by mail-lj1-f193.google.com with SMTP id h23so3600768ljc.8 for ; Thu, 27 Feb 2020 06:20:14 -0800 (PST) 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=Agm4aCXIkmbaB+Pv433vldzqvF/93gjO3Xrh7cZjFL8=; b=GMlNI+2WF9G6lhAQ/dn6XKwlpYxRX//SI/Ip9vs+lN1L8aVTDU0BVncZm9DIaGkRKs xeiCgCCDKwdWOO4zCmBAHsfERprT0FvoyhzvFRYnbx+XkjgQajbSCJs6+6otAHJSFbG/ H3qR9pH46AF0nSFC5ixBi0ASX1AjY+Iejw148AhoCdKhsIspO4m9QTWrfSm4r1Pd56ak DG3vYKFi0IE94P4hYrEwSBZPMu6weNufwQBYa3j+Txtjm7qbSsZjVHzWvh5tJN3kafjM OtM6e87XIANto+x6ho6JOiuYhlidV4ONqkl4pRyqclSp/bYMuNNSp8cAhu02oE/yxj5Q jPhw== 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=Agm4aCXIkmbaB+Pv433vldzqvF/93gjO3Xrh7cZjFL8=; b=Gk1fOlFvGIiBDk0yH3OKFRpF1f/Fqe76Ig1nIurKjO9qJ7C4UlcvNY5GvBhT5ssrEq /YYOAWVI5QAPc/w05dHtxAxMrt2JgJm6TWFxBO1p+r5HPMma77KEk+8+JRUl55udwViq 3KO/9zW8Pyye35sTJjiQNc2ts7GXUg2zYJthUbZiTX9lJvWeJk9UKWwgbPDmSDRMG/9P AT20BilgfYjshv+2jIMZnPC3hXWoTESwjTBCrS51AmvmU+eDLpoLwrJBVes8IVF/aIKu k43+9C53keiJuRO+RjbJaZq2kXSNMP4D6Xig0/1O8PdjLZY19NdrwzeU9ggLm9+oFOYW bIRg== X-Gm-Message-State: ANhLgQ1dPnHuw5wrwVh3RGd+qFW7HPDP007V4ebONQPnpFJV9B+FukT2 nQZmHik+i3RBSPG5Zdq+gaU= X-Google-Smtp-Source: ADFU+vtfEJa2/N0VcPpE9KEQ7MofuI6WwqHUxFw0hmLvc6RRtUibWLAs0PAj+HP5BNrBkIrAlQZ1nw== X-Received: by 2002:a2e:94c8:: with SMTP id r8mr3155536ljh.28.1582813213779; Thu, 27 Feb 2020 06:20:13 -0800 (PST) Received: from oberon.zico.biz ([83.222.187.186]) by smtp.gmail.com with ESMTPSA id l3sm3306437lja.78.2020.02.27.06.20.12 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Thu, 27 Feb 2020 06:20:13 -0800 (PST) From: "Tzvetomir Stoyanov (VMware)" To: rostedt@goodmis.org Cc: linux-trace-devel@vger.kernel.org Subject: [PATCH v20 07/15] trace-cmd: Add definitions of htonll() and ntohll() Date: Thu, 27 Feb 2020 16:19:53 +0200 Message-Id: <20200227142001.61577-8-tz.stoyanov@gmail.com> X-Mailer: git-send-email 2.24.1 In-Reply-To: <20200227142001.61577-1-tz.stoyanov@gmail.com> References: <20200227142001.61577-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 Reorganized libtracecmd internal headers: - Renamed trace-cmd-local.h to trace-write-local.h This internal header implements static __do_write_check() function, used in trace-input.c, trace-output.c and trace-msg.c files. The header cannot be included in other files, which do not call __do_write_check(). The new name trace-write-local.h reflects more closely the purpose of the file. - Added trace-cmd-local.h file, to share code inside libtracecmd. - Added definitions of htonll() and ntohll(), if not already defined, in trace-cmd-local.h Signed-off-by: Tzvetomir Stoyanov --- lib/trace-cmd/include/trace-cmd-local.h | 45 ++++++----------------- lib/trace-cmd/include/trace-write-local.h | 43 ++++++++++++++++++++++ lib/trace-cmd/trace-input.c | 2 +- lib/trace-cmd/trace-msg.c | 2 +- lib/trace-cmd/trace-output.c | 2 + 5 files changed, 58 insertions(+), 36 deletions(-) create mode 100644 lib/trace-cmd/include/trace-write-local.h diff --git a/lib/trace-cmd/include/trace-cmd-local.h b/lib/trace-cmd/include/trace-cmd-local.h index 09574dbd..95dce66c 100644 --- a/lib/trace-cmd/include/trace-cmd-local.h +++ b/lib/trace-cmd/include/trace-cmd-local.h @@ -6,10 +6,8 @@ #ifndef _TRACE_CMD_LOCAL_H #define _TRACE_CMD_LOCAL_H -/* Local for trace-input.c and trace-output.c */ - -#include "trace-cmd.h" -#include "event-utils.h" +/* Can be overridden */ +void warning(const char *fmt, ...); /* trace.dat file format version */ #define FILE_VERSION 6 @@ -18,36 +16,15 @@ #define STR(x) _STR(x) #define FILE_VERSION_STRING STR(FILE_VERSION) -static ssize_t __do_write(int fd, const void *data, size_t size) -{ - ssize_t tot = 0; - ssize_t w; - - do { - w = write(fd, data + tot, size - tot); - tot += w; - - if (!w) - break; - if (w < 0) - return w; - } while (tot != size); - - return tot; -} - -static ssize_t -__do_write_check(int fd, const void *data, size_t size) -{ - ssize_t ret; - - ret = __do_write(fd, data, size); - if (ret < 0) - return ret; - if (ret != size) - return -1; +#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 - return 0; -} #endif /* _TRACE_CMD_LOCAL_H */ diff --git a/lib/trace-cmd/include/trace-write-local.h b/lib/trace-cmd/include/trace-write-local.h new file mode 100644 index 00000000..94ad910b --- /dev/null +++ b/lib/trace-cmd/include/trace-write-local.h @@ -0,0 +1,43 @@ +/* SPDX-License-Identifier: LGPL-2.1 */ +/* + * Copyright (C) 2010 Red Hat Inc, Steven Rostedt + * + */ +#ifndef _TRACE_WRITE_LOCAL_H +#define _TRACE_WRITE_LOCAL_H + +/* Local for trace-input.c, trace-output.c and trace-msg.c */ + +static ssize_t __do_write(int fd, const void *data, size_t size) +{ + ssize_t tot = 0; + ssize_t w; + + do { + w = write(fd, data + tot, size - tot); + tot += w; + + if (!w) + break; + if (w < 0) + return w; + } while (tot != size); + + return tot; +} + +static ssize_t +__do_write_check(int fd, const void *data, size_t size) +{ + ssize_t ret; + + ret = __do_write(fd, data, size); + if (ret < 0) + return ret; + if (ret != size) + return -1; + + return 0; +} + +#endif /* _TRACE_WRITE_LOCAL_H */ diff --git a/lib/trace-cmd/trace-input.c b/lib/trace-cmd/trace-input.c index aca13c4e..f5611b46 100644 --- a/lib/trace-cmd/trace-input.c +++ b/lib/trace-cmd/trace-input.c @@ -15,7 +15,7 @@ #include -#include "trace-cmd-local.h" +#include "trace-write-local.h" #include "trace-local.h" #include "kbuffer.h" #include "list.h" diff --git a/lib/trace-cmd/trace-msg.c b/lib/trace-cmd/trace-msg.c index 9c8a6908..85a2bae6 100644 --- a/lib/trace-cmd/trace-msg.c +++ b/lib/trace-cmd/trace-msg.c @@ -22,7 +22,7 @@ #include #include -#include "trace-cmd-local.h" +#include "trace-write-local.h" #include "trace-local.h" #include "trace-msg.h" diff --git a/lib/trace-cmd/trace-output.c b/lib/trace-cmd/trace-output.c index acdd2d57..4a9a857d 100644 --- a/lib/trace-cmd/trace-output.c +++ b/lib/trace-cmd/trace-output.c @@ -21,7 +21,9 @@ #include #include "tracefs.h" +#include "trace-cmd.h" #include "trace-cmd-local.h" +#include "trace-write-local.h" #include "list.h" #include "trace-msg.h" From patchwork Thu Feb 27 14:19:54 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: "Tzvetomir Stoyanov (VMware)" X-Patchwork-Id: 11408689 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 85D0892A for ; Thu, 27 Feb 2020 14:20:20 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.kernel.org (Postfix) with ESMTP id 513A4246AD for ; Thu, 27 Feb 2020 14:20:20 +0000 (UTC) Authentication-Results: mail.kernel.org; dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b="uVrR/158" Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S2389869AbgB0OUT (ORCPT ); Thu, 27 Feb 2020 09:20:19 -0500 Received: from mail-lj1-f195.google.com ([209.85.208.195]:43798 "EHLO mail-lj1-f195.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S2389728AbgB0OUS (ORCPT ); Thu, 27 Feb 2020 09:20:18 -0500 Received: by mail-lj1-f195.google.com with SMTP id e3so3584358lja.10 for ; Thu, 27 Feb 2020 06:20:15 -0800 (PST) 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=05x5Iu5Gsl2QvV6KkoVHKEKEhWtqxjNZxwV7dFwMKO4=; b=uVrR/158yTyVfjFb7tXqfgK3Ry8sHiIjMa26SkeAdI7f09gCAR739SauPxuGIbor3N z/q8vqptHJH5T/XcrO+lkDQh3VeRG7FmZkMyQMIJPkjMTLCKe6ZVIHo//YtKgxSHjkOs zSa1WgDw60iayrt0Llm6a2EINXRHjmUDqFfDy9EcFUwf9xzsMpgl+Nf3XOnXo+S/g0Jt qHZIzmOLjDKTS2ZAl0QpIl4OF5J+MhAdvTijNeME5vGxhSCPzVXJfNtrysqPtprqNcy4 fIWDD4T2LIHR/J7iIeOacw0MlSdtdKZEURNlS81mI14+aduPbk3ZNTtdHOUMpfJE7V9/ /BVg== 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=05x5Iu5Gsl2QvV6KkoVHKEKEhWtqxjNZxwV7dFwMKO4=; b=bknr55t39EBHPpe9wpzZTvnFtRJSLBa1lFzUjDKKT2j3aCz76qUNNuFUBZTVMSvnet iOzhvNVlN6bQ1qCQP4hTSsbmNyYJdgWx+xHFuMtKcMGk2QDCLzrSnnXuV6iSfpG2/USY OrRsNi+iTPCm4u+JcV3TtwCY3UgZ1ErSoSTWf9GWL3tEqyPnko6kK5iA8vKWrq6NKJ8S LGYW+9Jka8p1J3nDcCOjuUwslShay+4qdkpph3PqmOWM+AZrthUstNJrwv2Tr97KliBx Naf75RVhGNLnjFMYayajFq9rJIykNuHaai6EfUC8ao11pFZyobNZhZhtKu05BqR8IxV1 En2A== X-Gm-Message-State: ANhLgQ0aiMV67AV56z0KiPK93vUF0LMGDfj1Sip4Rmi6znLZ8aeQqRat qqqKWQv+RG/oRo2LASqjOWRHMX/rW+o= X-Google-Smtp-Source: ADFU+vtfxDuwR6JnS13jSgwM95HtHZN3hU4usFE1vgTpmjymMYLBclUXK+w3F9fVwb7YD7nOlZiH1w== X-Received: by 2002:a2e:86c8:: with SMTP id n8mr3015337ljj.205.1582813215059; Thu, 27 Feb 2020 06:20:15 -0800 (PST) Received: from oberon.zico.biz ([83.222.187.186]) by smtp.gmail.com with ESMTPSA id l3sm3306437lja.78.2020.02.27.06.20.13 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Thu, 27 Feb 2020 06:20:14 -0800 (PST) From: "Tzvetomir Stoyanov (VMware)" To: rostedt@goodmis.org Cc: linux-trace-devel@vger.kernel.org Subject: [PATCH v20 08/15] trace-cmd: Exchange tracing IDs between host and guest Date: Thu, 27 Feb 2020 16:19:54 +0200 Message-Id: <20200227142001.61577-9-tz.stoyanov@gmail.com> X-Mailer: git-send-email 2.24.1 In-Reply-To: <20200227142001.61577-1-tz.stoyanov@gmail.com> References: <20200227142001.61577-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 Extend the trace request and trace reply messages, to include also the IDs of host and guest tracing sessions. Those IDs are used to unambiguously match the tracing sessions, when reading trace.dat files. Signed-off-by: Tzvetomir Stoyanov (VMware) --- include/trace-cmd/trace-cmd.h | 12 ++++++++---- lib/trace-cmd/trace-msg.c | 31 ++++++++++++++++++++++--------- tracecmd/include/trace-local.h | 3 ++- tracecmd/trace-agent.c | 10 +++++++--- tracecmd/trace-record.c | 10 +++++++--- 5 files changed, 46 insertions(+), 20 deletions(-) diff --git a/include/trace-cmd/trace-cmd.h b/include/trace-cmd/trace-cmd.h index 6075a37e..55abd489 100644 --- a/include/trace-cmd/trace-cmd.h +++ b/include/trace-cmd/trace-cmd.h @@ -370,16 +370,20 @@ 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, + unsigned long long trace_id); 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, + unsigned long long *trace_id); 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, + unsigned long long trace_id); 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, + unsigned long long *trace_id); /* --- Plugin handling --- */ extern struct tep_plugin_option trace_ftrace_options[]; diff --git a/lib/trace-cmd/trace-msg.c b/lib/trace-cmd/trace-msg.c index 85a2bae6..d6a68ac3 100644 --- a/lib/trace-cmd/trace-msg.c +++ b/lib/trace-cmd/trace-msg.c @@ -23,6 +23,7 @@ #include #include "trace-write-local.h" +#include "trace-cmd-local.h" #include "trace-local.h" #include "trace-msg.h" @@ -63,12 +64,14 @@ struct tracecmd_msg_rinit { struct tracecmd_msg_trace_req { be32 flags; be32 argc; + u64 trace_id; } __attribute__((packed)); struct tracecmd_msg_trace_resp { be32 flags; be32 cpus; be32 page_size; + u64 trace_id; } __attribute__((packed)); struct tracecmd_msg_header { @@ -811,7 +814,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, unsigned long long trace_id) { size_t args_size = 0; char *p; @@ -823,6 +827,7 @@ static int make_trace_req(struct tracecmd_msg *msg, int argc, char **argv, bool 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.argc = htonl(argc); + msg->trace_req.trace_id = htonll(trace_id); msg->buf = calloc(args_size, 1); if (!msg->buf) return -ENOMEM; @@ -835,13 +840,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, + unsigned long long trace_id) { 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, trace_id); if (ret < 0) return ret; @@ -854,7 +860,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, + unsigned long long *trace_id) { struct tracecmd_msg msg; char *p, *buf_end, **args; @@ -901,7 +908,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; - + *trace_id = ntohll(msg.trace_req.trace_id); /* * On success we're passing msg.buf to the caller through argv[0] so we * reset it here before calling msg_free(). @@ -921,7 +928,8 @@ out: } 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, + unsigned long long trace_id) { int data_size; @@ -935,19 +943,22 @@ static int make_trace_resp(struct tracecmd_msg *msg, int page_size, int nr_cpus, msg->trace_resp.flags = use_fifos ? htonl(MSG_TRACE_USE_FIFOS) : htonl(0); msg->trace_resp.cpus = htonl(nr_cpus); msg->trace_resp.page_size = htonl(page_size); + msg->trace_resp.trace_id = htonll(trace_id); return 0; } 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, + unsigned long long trace_id) { 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, trace_id); if (ret < 0) return ret; @@ -956,7 +967,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, + unsigned long long *trace_id) { struct tracecmd_msg msg; char *p, *buf_end; @@ -981,6 +993,7 @@ int tracecmd_msg_recv_trace_resp(struct tracecmd_msg_handle *msg_handle, *use_fifos = ntohl(msg.trace_resp.flags) & MSG_TRACE_USE_FIFOS; *nr_cpus = ntohl(msg.trace_resp.cpus); *page_size = ntohl(msg.trace_resp.page_size); + *trace_id = ntohll(msg.trace_resp.trace_id); *ports = calloc(*nr_cpus, sizeof(**ports)); if (!*ports) { ret = -ENOMEM; diff --git a/tracecmd/include/trace-local.h b/tracecmd/include/trace-local.h index 6fe22bb0..4f2b5541 100644 --- a/tracecmd/include/trace-local.h +++ b/tracecmd/include/trace-local.h @@ -101,7 +101,8 @@ void trace_dump(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, + unsigned long long trace_id); struct hook_list; diff --git a/tracecmd/trace-agent.c b/tracecmd/trace-agent.c index 1c6e0a3a..52d27195 100644 --- a/tracecmd/trace-agent.c +++ b/tracecmd/trace-agent.c @@ -128,6 +128,7 @@ cleanup: static void agent_handle(int sd, int nr_cpus, int page_size) { struct tracecmd_msg_handle *msg_handle; + unsigned long long trace_id; unsigned int *ports; char **argv = NULL; int argc = 0; @@ -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, &trace_id); if (ret < 0) die("Failed to receive trace request"); @@ -154,12 +156,14 @@ static void agent_handle(int sd, int nr_cpus, int page_size) if (!use_fifos) make_vsocks(nr_cpus, fds, ports); + trace_id = tracecmd_generate_traceid(); ret = tracecmd_msg_send_trace_resp(msg_handle, nr_cpus, page_size, - ports, use_fifos); + ports, use_fifos, trace_id); 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, trace_id); free(argv[0]); free(argv); diff --git a/tracecmd/trace-record.c b/tracecmd/trace-record.c index 3e24eb43..7427fea4 100644 --- a/tracecmd/trace-record.c +++ b/tracecmd/trace-record.c @@ -3686,12 +3686,14 @@ static void connect_to_agent(struct buffer_instance *instance) die("Failed to allocate message handle"); ret = tracecmd_msg_send_trace_req(msg_handle, instance->argc, - instance->argv, use_fifos); + instance->argv, use_fifos, + top_instance.trace_id); 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, + &instance->trace_id); if (ret < 0) die("Failed to receive trace response"); @@ -6237,7 +6239,8 @@ 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, + unsigned long long trace_id) { struct common_record_context ctx; char **argv_plus; @@ -6267,6 +6270,7 @@ int trace_record_agent(struct tracecmd_msg_handle *msg_handle, ctx.instance->flags |= BUFFER_FL_AGENT; ctx.instance->msg_handle = msg_handle; msg_handle->version = V3_PROTOCOL; + top_instance.trace_id = trace_id; record_trace(argc, argv, &ctx); free(argv_plus); From patchwork Thu Feb 27 14:19:55 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: "Tzvetomir Stoyanov (VMware)" X-Patchwork-Id: 11408693 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 88C6A930 for ; Thu, 27 Feb 2020 14:20:21 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.kernel.org (Postfix) with ESMTP id 67C2B20801 for ; Thu, 27 Feb 2020 14:20:21 +0000 (UTC) Authentication-Results: mail.kernel.org; dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b="lOqspmBd" Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S2389666AbgB0OUU (ORCPT ); Thu, 27 Feb 2020 09:20:20 -0500 Received: from mail-lj1-f195.google.com ([209.85.208.195]:45102 "EHLO mail-lj1-f195.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S2389286AbgB0OUU (ORCPT ); Thu, 27 Feb 2020 09:20:20 -0500 Received: by mail-lj1-f195.google.com with SMTP id e18so3577988ljn.12 for ; Thu, 27 Feb 2020 06:20:17 -0800 (PST) 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=EwRj2yp74oDuUS3UOfgzpdEPENlDRJZbNF/sDzc2IjY=; b=lOqspmBdU/qWIZt2jSxWItAep8i6SUou0irdvOVT8WomLTxkXe5vQ9baVnhMD+lg96 bHYmGklqPYP3roZ5rnJ0kwD/lZtDCwfZ1VOyPjAYKAU3B4544cv9fquFAuDRx9NXE4qZ 1ezemp+eSr5kLbAN3uxd7U/kFbSnLGlJRNw4zbWz9XULzK5t2N+E/65IhNZiSrpPRauh hZqOWP4XcaLUHnHnimPPmL6nH6kqthx6yglQqzGB35MWHrt7ypozvk3Gd7YLy4QLVQkR 5toST+vNp++Ut40z+HU/U9s/jjS2RcfxEQx00kUyWIy/rbRK0FrS99TaGO+v4SQiJwed lliw== 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=EwRj2yp74oDuUS3UOfgzpdEPENlDRJZbNF/sDzc2IjY=; b=j+8RMicRGztzA8+cfWaVa/CIveItlRkcnkKzznI2NfFk5xIioCPeXNyTElWSUlsnu5 MK69peWj4KyM+9cN93i0o1QYL1OxnPiMz+hl9ljSRgTJjdg4L/EjU8/C09TZG/oMZXjR 5Sl+coaLSZ1CcPPd9YAKNCgnABTwwpSE8g9Yfoiod3uR6ayQ/ZUROJsl7NvRGPcTr1PU WILHpp+IbO4KojrMHVUKzNbeo7ChpE4ImqGnzFK5UVut461hpSWpyrTjO2wHPT/hxS8D mnBVq9s3TrkJiR0mhKoAthvy1FaGrYKPAjVV3WURF8zFuL81/vs5v3sI3d4kN11HX/5c E5Yg== X-Gm-Message-State: ANhLgQ2PTXc8CnhRwAKlgPLTBRI+gDESpHjzFnqvtZOie+Rj1KytbLPQ 550msQx1rM90bjsK7yElaSvB6VytLa0= X-Google-Smtp-Source: ADFU+vuGS8BtHXaO6I3vC1OT1N+ysjBd9POnBO5YaLO9TbHK8rjL0E+tra88WLkAvskzHMXkyqalvw== X-Received: by 2002:a2e:b4cf:: with SMTP id r15mr3035704ljm.52.1582813216264; Thu, 27 Feb 2020 06:20:16 -0800 (PST) Received: from oberon.zico.biz ([83.222.187.186]) by smtp.gmail.com with ESMTPSA id l3sm3306437lja.78.2020.02.27.06.20.15 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Thu, 27 Feb 2020 06:20:15 -0800 (PST) From: "Tzvetomir Stoyanov (VMware)" To: rostedt@goodmis.org Cc: linux-trace-devel@vger.kernel.org Subject: [PATCH v20 09/15] trace-cmd: Implement new option in trace.dat file: TRACECMD_OPTION_TIME_SHIFT Date: Thu, 27 Feb 2020 16:19:55 +0200 Message-Id: <20200227142001.61577-10-tz.stoyanov@gmail.com> X-Mailer: git-send-email 2.24.1 In-Reply-To: <20200227142001.61577-1-tz.stoyanov@gmail.com> References: <20200227142001.61577-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: 8 bytes - long long integer, ID of the tracing session 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 | 3 + lib/trace-cmd/trace-input.c | 185 +++++++++++++++++++++++++++++++++- tracecmd/trace-dump.c | 49 +++++++++ 3 files changed, 235 insertions(+), 2 deletions(-) diff --git a/include/trace-cmd/trace-cmd.h b/include/trace-cmd/trace-cmd.h index 55abd489..ac46637e 100644 --- a/include/trace-cmd/trace-cmd.h +++ b/include/trace-cmd/trace-cmd.h @@ -110,6 +110,7 @@ enum { TRACECMD_OPTION_VERSION, TRACECMD_OPTION_PROCMAPS, TRACECMD_OPTION_TRACEID, + TRACECMD_OPTION_TIME_SHIFT, }; enum { @@ -153,6 +154,8 @@ void tracecmd_set_flag(struct tracecmd_input *handle, int flag); void tracecmd_clear_flag(struct tracecmd_input *handle, int flag); unsigned long tracecmd_get_flags(struct tracecmd_input *handle); unsigned long long tracecmd_get_traceid(struct tracecmd_input *handle); +unsigned long long tracecmd_get_tsync_peer(struct tracecmd_input *handle); +int tracecmd_enable_tsync(struct tracecmd_input *handle, bool enable); void tracecmd_parse_trace_clock(struct tracecmd_input *handle, char *file, int size); diff --git a/lib/trace-cmd/trace-input.c b/lib/trace-cmd/trace-input.c index f5611b46..cf7be730 100644 --- a/lib/trace-cmd/trace-input.c +++ b/lib/trace-cmd/trace-input.c @@ -77,6 +77,18 @@ struct input_buffer_instance { size_t offset; }; +struct ts_offset_sample { + long long time; + long long offset; +}; + +struct host_trace_info { + bool sync_enable; + unsigned long long trace_id; + int ts_samples_count; + struct ts_offset_sample *ts_samples; +}; + struct tracecmd_input { struct tep_handle *pevent; struct tep_plugin_list *plugin_list; @@ -95,6 +107,7 @@ struct tracecmd_input { bool use_pipe; struct cpu_data *cpu_data; long long ts_offset; + struct host_trace_info host; double ts2secs; char * cpustats; char * uname; @@ -1075,6 +1088,69 @@ 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 offset = ((long long)ts - min->time) * + (max->offset - min->offset); + long long delta = max->time - min->time; + long long tscor = min->offset + + (offset + delta / 2) / delta; + + if (tscor < 0) + return ts - llabs(tscor); + + return ts + tscor; +} + +static unsigned long long timestamp_correct(unsigned long long ts, + struct tracecmd_input *handle) +{ + struct host_trace_info *host = &handle->host; + int min, mid, max; + + if (handle->ts_offset) + return ts + handle->ts_offset; + + if (!host->sync_enable) + return ts; + + /* We have one sample, nothing to calc here */ + if (host->ts_samples_count == 1) + return ts + host->ts_samples[0].offset; + + /* We have two samples, nothing to search here */ + if (host->ts_samples_count == 2) + return timestamp_correction_calc(ts, &host->ts_samples[0], + &host->ts_samples[1]); + + /* We have more than two samples */ + if (ts <= host->ts_samples[0].time) + return timestamp_correction_calc(ts, + &host->ts_samples[0], + &host->ts_samples[1]); + else if (ts >= host->ts_samples[host->ts_samples_count-1].time) + return timestamp_correction_calc(ts, + &host->ts_samples[host->ts_samples_count-2], + &host->ts_samples[host->ts_samples_count-1]); + min = 0; + max = host->ts_samples_count-1; + mid = (min + max)/2; + while (min <= max) { + if (ts < host->ts_samples[mid].time) + max = mid - 1; + else if (ts > host->ts_samples[mid].time) + min = mid + 1; + else + break; + mid = (min + max)/2; + } + + return timestamp_correction_calc(ts, &host->ts_samples[mid], + &host->ts_samples[mid+1]); +} + /* * Page is mapped, now read in the page header info. */ @@ -1096,7 +1172,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; @@ -1729,7 +1805,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; @@ -2052,6 +2128,48 @@ 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) +{ + struct host_trace_info *host = &handle->host; + long long *buf8 = (long long *)buf; + int i, j; + + for (i = 0; i < host->ts_samples_count; i++) { + host->ts_samples[i].time = tep_read_number(handle->pevent, + buf8 + i, 8); + host->ts_samples[i].offset = tep_read_number(handle->pevent, + buf8 + host->ts_samples_count+i, 8); + } + qsort(host->ts_samples, host->ts_samples_count, + sizeof(struct ts_offset_sample), tsync_offset_cmp); + /* Filter possible samples with equal time */ + for (i = 0, j = 0; i < host->ts_samples_count; i++) { + if (i == 0 || host->ts_samples[i].time != host->ts_samples[i-1].time) + host->ts_samples[j++] = host->ts_samples[i]; + } + host->ts_samples_count = j; + if (j) + host->sync_enable = true; +} + +static void trace_tsync_offset_free(struct host_trace_info *host) +{ + free(host->ts_samples); + host->ts_samples = NULL; +} + static int trace_pid_map_cmp(const void *a, const void *b) { struct tracecmd_proc_addr_map *m_a = (struct tracecmd_proc_addr_map *)a; @@ -2224,6 +2342,7 @@ static int handle_options(struct tracecmd_input *handle) struct input_buffer_instance *buffer; struct hook_list *hook; char *buf; + int samples_size; int cpus; /* By default, use usecs, unless told otherwise */ @@ -2271,6 +2390,30 @@ static int handle_options(struct tracecmd_input *handle) offset = strtoll(buf, NULL, 0); handle->ts_offset += offset; break; + case TRACECMD_OPTION_TIME_SHIFT: + /* + * long long int (8 bytes) trace session ID + * 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 (size < 12 || handle->flags & TRACECMD_FL_IGNORE_DATE) + break; + handle->host.trace_id = tep_read_number(handle->pevent, + buf, 8); + handle->host.ts_samples_count = tep_read_number(handle->pevent, + buf + 8, 4); + samples_size = (8 * handle->host.ts_samples_count); + if (size != (12 + (2 * samples_size))) { + warning("Failed to extract Time Shift information from the file, unexpected size %d", size); + break; + } + handle->host.ts_samples = malloc(2 * samples_size); + if (!handle->host.ts_samples) + return -ENOMEM; + tsync_offset_load(handle, buf + 12); + break; case TRACECMD_OPTION_CPUSTAT: buf[size-1] = '\n'; cpustats = realloc(cpustats, cpustats_size + size + 1); @@ -2974,6 +3117,8 @@ void tracecmd_close(struct tracecmd_input *handle) trace_pid_map_free(handle->pid_maps); handle->pid_maps = NULL; + trace_tsync_offset_free(&handle->host); + if (handle->flags & TRACECMD_FL_BUFFER_INSTANCE) tracecmd_close(handle->parent); else { @@ -3315,6 +3460,7 @@ tracecmd_buffer_instance_handle(struct tracecmd_input *handle, int indx) return NULL; } } + memset(&new_handle->host, 0, sizeof(new_handle->host)); new_handle->parent = handle; new_handle->cpustats = NULL; new_handle->hooks = NULL; @@ -3435,3 +3581,38 @@ unsigned long long tracecmd_get_traceid(struct tracecmd_input *handle) { return handle->trace_id; } + +/** + * tracecmd_get_tsync_peer - get the trace session id of the peer host + * @handle: input handle for the trace.dat file + * + * Returns the trace id of the peer host, written in the trace file + * + * This information is stored in guest trace.dat file + */ +unsigned long long tracecmd_get_tsync_peer(struct tracecmd_input *handle) +{ + return handle->host.trace_id; +} + +/** + * tracecmd_enable_tsync - enable / disable the timestamps correction + * @handle: input handle for the trace.dat file + * @enable: enable / disable the timestamps correction + * + * Enables or disables timestamps correction on file load, using the array of + * recorded time offsets. If "enable" is true, but there are no time offsets, + * function fails and -1 is returned. + * + * Returns -1 in case of an error, or 0 otherwise + */ +int tracecmd_enable_tsync(struct tracecmd_input *handle, bool enable) +{ + if (enable && + (!handle->host.ts_samples || !handle->host.ts_samples_count)) + return -1; + + handle->host.sync_enable = enable; + + return 0; +} diff --git a/tracecmd/trace-dump.c b/tracecmd/trace-dump.c index 2dfeaa0f..b4beb8b2 100644 --- a/tracecmd/trace-dump.c +++ b/tracecmd/trace-dump.c @@ -366,6 +366,52 @@ static void dump_option_xlong(int fd, int size, char *desc) read_file_number(fd, &val, size); do_print(OPTIONS, "0x%llX\n", val); } + +static void dump_option_timeshift(int fd, int size) +{ + long long *offsets = NULL; + long long *times = NULL; + long long trace_id; + unsigned int count; + int i; + + /* + * long long int (8 bytes) trace session ID + * 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 (size < 12) { + do_print(OPTIONS, "Broken time shift option, size %s", size); + return; + } + do_print(OPTIONS, "\t\t[Option TimeShift, %d bytes]\n", size); + read_file_number(fd, &trace_id, 8); + do_print(OPTIONS, "0x%llX [peer's trace id]\n", trace_id); + read_file_number(fd, &count, 4); + do_print(OPTIONS, "%lld [samples count]\n", count); + times = calloc(count, sizeof(long long)); + if (!times) + goto out; + offsets = calloc(count, sizeof(long long)); + if (!offsets) + goto out; + + for (i = 0; i < count; i++) + read_file_number(fd, times + i, 8); + for (i = 0; i < count; i++) + read_file_number(fd, offsets + i, 8); + + for (i = 0; i < count; i++) + do_print(OPTIONS, "\t%lld %lld [offset @ time]\n", + offsets[i], times[i]); + +out: + free(times); + free(offsets); +} + static void dump_options(int fd) { unsigned short option; @@ -419,6 +465,9 @@ static void dump_options(int fd) case TRACECMD_OPTION_TRACEID: dump_option_xlong(fd, size, "TRACEID"); break; + case TRACECMD_OPTION_TIME_SHIFT: + dump_option_timeshift(fd, size); + break; default: do_print(OPTIONS, " %d %d\t[Unknown option, size - skipping]\n", option, size); From patchwork Thu Feb 27 14:19:56 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: "Tzvetomir Stoyanov (VMware)" X-Patchwork-Id: 11408691 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 3E10692A for ; Thu, 27 Feb 2020 14:20:21 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.kernel.org (Postfix) with ESMTP id F3C3D2468F for ; Thu, 27 Feb 2020 14:20:20 +0000 (UTC) Authentication-Results: mail.kernel.org; dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b="IsN/G7xn" Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1730987AbgB0OUU (ORCPT ); Thu, 27 Feb 2020 09:20:20 -0500 Received: from mail-lj1-f194.google.com ([209.85.208.194]:45114 "EHLO mail-lj1-f194.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S2389821AbgB0OUU (ORCPT ); Thu, 27 Feb 2020 09:20:20 -0500 Received: by mail-lj1-f194.google.com with SMTP id e18so3578056ljn.12 for ; Thu, 27 Feb 2020 06:20:18 -0800 (PST) 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=yr130jwMx3cdMI9I1jjN5hf9NWvJpGLDMOAeY285aAI=; b=IsN/G7xn9VFsY6aBSsm8quNzKoGxvSDh73W/wU1bePbaasd5pRjO5zZhg7QsV1UMwF vM+NY3yuhAzZSrJBjkWtGM04MVqy46s4M+yZp1GO/fskae8Yfq45vg/s7FqQCtAgKeDk ksQLJwQsG1TitL1IEJoVrSMot6JzoHyYw1o+ccHET0iZuga2MkAidTV0MUe6+Yq1oywM 3btouMlEsq/hTyLXOmVhfhlG4wv68IfspbjK5VdmOvZmXRdTMUCq9/WrWQwk/tLMXy3u TVJHEJNsJWnnAWMFqcYK3GGxcr31axrLp3CI/9003mXJHGoPG5CnMgD4o2vfEZwjkGYE /OPw== 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=yr130jwMx3cdMI9I1jjN5hf9NWvJpGLDMOAeY285aAI=; b=T2WH59Uzgal6PnVYaMTV3SaarzNGZ4Eewfso7K5c3I83uC8enRBLwYmtP2yBto0A5G aH4pAkXnkjuByhhyp4B3IvJR7cbFJmC45cslplijJbvigSK4cCdCO799aDyqLAkmgi/0 Ou49KZuAQTzAi/FmiwAy+7H6C0PRt8qhfGyDYOTSmJB0JaGHY0V9ayfNNccPI54pIcly VIiD8Y9ZKEiX6Ma5Kn+c5EoPjLlfqK4s+b95FR2GH6wYaYAh2AdUm9CoR6YvGQ+aHZA5 wC6am3EBdNwICBIdQbWtmCVwK61/Xbim6Ku9YBc8zt0Wg4WS6J0QegU4FUPuLaxLqCmx 29Zg== X-Gm-Message-State: ANhLgQ0lOo21ddShLlFQr6aBOD+lQZy6bk40kIQRSWbxEzrHtE+66PuJ LYai/8StzAsmvIBRkpZH3RAgMrzoOLM= X-Google-Smtp-Source: ADFU+vtNOhQAs27SMQR3pSrAmjlVxl7jtdSG9bVyT5G29nfSZPlM+T9qB2aHm2ir0sXq3b+kM5UOKA== X-Received: by 2002:a2e:b4f6:: with SMTP id s22mr2917982ljm.218.1582813217450; Thu, 27 Feb 2020 06:20:17 -0800 (PST) Received: from oberon.zico.biz ([83.222.187.186]) by smtp.gmail.com with ESMTPSA id l3sm3306437lja.78.2020.02.27.06.20.16 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Thu, 27 Feb 2020 06:20:16 -0800 (PST) From: "Tzvetomir Stoyanov (VMware)" To: rostedt@goodmis.org Cc: linux-trace-devel@vger.kernel.org Subject: [PATCH v20 10/15] trace-cmd: Add guest information in host's trace.dat file Date: Thu, 27 Feb 2020 16:19:56 +0200 Message-Id: <20200227142001.61577-11-tz.stoyanov@gmail.com> X-Mailer: git-send-email 2.24.1 In-Reply-To: <20200227142001.61577-1-tz.stoyanov@gmail.com> References: <20200227142001.61577-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 New trace.dat option is introduced: TRACECMD_OPTION_GUEST. Written in the host's trace.dat file, it contains information about guests, traced at the same time: guest trace ID, number of VCPUs and PIDs of the host tasks, running those VCPU. The data is stored in the file as: Guest name, null terminated string long long (8 bytes) trace-id int (4 bytes) number of guest CPUs array of size number of guest CPUs: int (4 bytes) Guest CPU id int (4 bytes) Host PID, running the guest CPU Signed-off-by: Tzvetomir Stoyanov (VMware) --- include/trace-cmd/trace-cmd.h | 5 ++ lib/trace-cmd/trace-input.c | 128 ++++++++++++++++++++++++++++++++++ tracecmd/trace-dump.c | 62 ++++++++++++++++ tracecmd/trace-record.c | 61 ++++++++++++++++ 4 files changed, 256 insertions(+) diff --git a/include/trace-cmd/trace-cmd.h b/include/trace-cmd/trace-cmd.h index ac46637e..0375f500 100644 --- a/include/trace-cmd/trace-cmd.h +++ b/include/trace-cmd/trace-cmd.h @@ -111,6 +111,7 @@ enum { TRACECMD_OPTION_PROCMAPS, TRACECMD_OPTION_TRACEID, TRACECMD_OPTION_TIME_SHIFT, + TRACECMD_OPTION_GUEST, }; enum { @@ -154,6 +155,10 @@ void tracecmd_set_flag(struct tracecmd_input *handle, int flag); void tracecmd_clear_flag(struct tracecmd_input *handle, int flag); unsigned long tracecmd_get_flags(struct tracecmd_input *handle); unsigned long long tracecmd_get_traceid(struct tracecmd_input *handle); +int tracecmd_get_guest_cpumap(struct tracecmd_input *handle, + unsigned long long trace_id, + char **name, + int *vcpu_count, int **cpu_pid); unsigned long long tracecmd_get_tsync_peer(struct tracecmd_input *handle); int tracecmd_enable_tsync(struct tracecmd_input *handle, bool enable); diff --git a/lib/trace-cmd/trace-input.c b/lib/trace-cmd/trace-input.c index cf7be730..d13fff36 100644 --- a/lib/trace-cmd/trace-input.c +++ b/lib/trace-cmd/trace-input.c @@ -82,6 +82,14 @@ struct ts_offset_sample { long long offset; }; +struct guest_trace_info { + struct guest_trace_info *next; + char *name; + unsigned long long trace_id; + int vcpu_count; + int *cpu_pid; +}; + struct host_trace_info { bool sync_enable; unsigned long long trace_id; @@ -115,6 +123,7 @@ struct tracecmd_input { char * trace_clock; struct input_buffer_instance *buffers; int parsing_failures; + struct guest_trace_info *guest; struct tracecmd_ftrace finfo; @@ -2197,6 +2206,86 @@ static void procmap_free(struct pid_addr_maps *maps) free(maps); } +static void trace_guests_free(struct tracecmd_input *handle) +{ + struct guest_trace_info *guest; + + while (handle->guest) { + guest = handle->guest; + handle->guest = handle->guest->next; + free(guest->name); + free(guest->cpu_pid); + free(guest); + } +} + +static int trace_guest_load(struct tracecmd_input *handle, char *buf, int size) +{ + struct guest_trace_info *guest = NULL; + int cpu; + int i; + + guest = calloc(1, sizeof(struct guest_trace_info)); + if (!guest) + goto error; + + /* + * Guest name, null terminated string + * long long (8 bytes) trace-id + * int (4 bytes) number of guest CPUs + * array of size number of guest CPUs: + * int (4 bytes) Guest CPU id + * int (4 bytes) Host PID, running the guest CPU + */ + + guest->name = strndup(buf, size); + if (!guest->name) + goto error; + buf += strlen(guest->name) + 1; + size -= strlen(guest->name) + 1; + + if (size < sizeof(long long)) + goto error; + guest->trace_id = tep_read_number(handle->pevent, buf, sizeof(long long)); + buf += sizeof(long long); + size -= sizeof(long long); + + if (size < sizeof(int)) + goto error; + guest->vcpu_count = tep_read_number(handle->pevent, buf, sizeof(int)); + buf += sizeof(int); + size -= sizeof(int); + + guest->cpu_pid = calloc(guest->vcpu_count, sizeof(int)); + if (!guest->cpu_pid) + goto error; + + for (i = 0; i < guest->vcpu_count; i++) { + if (size < 2 * sizeof(int)) + goto error; + cpu = tep_read_number(handle->pevent, buf, sizeof(int)); + buf += sizeof(int); + if (cpu >= guest->vcpu_count) + goto error; + guest->cpu_pid[cpu] = tep_read_number(handle->pevent, + buf, sizeof(int)); + buf += sizeof(int); + size -= 2 * sizeof(int); + } + + guest->next = handle->guest; + handle->guest = guest; + return 0; + +error: + if (guest) { + free(guest->cpu_pid); + free(guest->name); + free(guest); + } + return -1; +} + /* Needs to be a constant, and 4K should be good enough */ #define STR_PROCMAP_LINE_MAX 4096 static int trace_pid_map_load(struct tracecmd_input *handle, char *buf) @@ -2464,6 +2553,9 @@ static int handle_options(struct tracecmd_input *handle) handle->trace_id = tep_read_number(handle->pevent, &cpus, 8); break; + case TRACECMD_OPTION_GUEST: + trace_guest_load(handle, buf, size); + break; default: warning("unknown option %d", option); break; @@ -3118,6 +3210,7 @@ void tracecmd_close(struct tracecmd_input *handle) handle->pid_maps = NULL; trace_tsync_offset_free(&handle->host); + trace_guests_free(handle); if (handle->flags & TRACECMD_FL_BUFFER_INSTANCE) tracecmd_close(handle->parent); @@ -3582,6 +3675,41 @@ unsigned long long tracecmd_get_traceid(struct tracecmd_input *handle) return handle->trace_id; } +/** + * tracecmd_get_guest_cpumap - get the mapping of guest VCPU to host process + * @handle: input handle for the trace.dat file + * @trace_id: ID of the guest tracing session + * @name: return, name of the guest + * @vcpu_count: return, number of VPUs + * @cpu_pid: return, array with guest VCPU to host process mapping + * + * Returns @name of the guest, number of VPUs (@vcpu_count) + * and array @cpu_pid with size @vcpu_count. Array index is VCPU id, array + * content is PID of the host process, running this VCPU. + * + * This information is stored in host trace.dat file + */ +int tracecmd_get_guest_cpumap(struct tracecmd_input *handle, + unsigned long long trace_id, + char **name, + int *vcpu_count, int **cpu_pid) +{ + struct guest_trace_info *guest = handle->guest; + + while (guest) { + if (guest->trace_id == trace_id) + break; + guest = guest->next; + } + if (!guest) + return -1; + + *name = guest->name; + *vcpu_count = guest->vcpu_count; + *cpu_pid = guest->cpu_pid; + return 0; +} + /** * tracecmd_get_tsync_peer - get the trace session id of the peer host * @handle: input handle for the trace.dat file diff --git a/tracecmd/trace-dump.c b/tracecmd/trace-dump.c index b4beb8b2..ffb1c6b1 100644 --- a/tracecmd/trace-dump.c +++ b/tracecmd/trace-dump.c @@ -412,6 +412,65 @@ out: free(offsets); } +void dump_option_guest(int fd, int size) +{ + unsigned long long trace_id; + char *buf, *p; + int cpu, pid; + int cpus; + int i; + + do_print(OPTIONS, "\t\t[Option GUEST, %d bytes]\n", size); + + /* + * Guest name, null terminated string + * long long (8 bytes) trace-id + * int (4 bytes) number of guest CPUs + * array of size number of guest CPUs: + * int (4 bytes) Guest CPU id + * int (4 bytes) Host PID, running the guest CPU + */ + buf = calloc(1, size); + if (!buf) + return; + if (read_file_bytes(fd, buf, size)) + goto out; + + p = buf; + do_print(OPTIONS, "%s [Guest name]\n", p); + size -= strlen(buf) + 1; + p += strlen(buf) + 1; + + if (size < sizeof(long long)) + goto out; + trace_id = tep_read_number(tep, p, sizeof(long long)); + size -= sizeof(long long); + p += sizeof(long long); + do_print(OPTIONS, "0x%llX [trace id]\n", trace_id); + + if (size < sizeof(int)) + goto out; + cpus = tep_read_number(tep, p, sizeof(int)); + size -= sizeof(int); + p += sizeof(int); + do_print(OPTIONS, "%d [Guest CPUs]\n", cpus); + + for (i = 0; i < cpus; i++) { + if (size < 2 * sizeof(int)) + goto out; + cpu = tep_read_number(tep, p, sizeof(int)); + size -= sizeof(int); + p += sizeof(int); + pid = tep_read_number(tep, p, sizeof(int)); + size -= sizeof(int); + p += sizeof(int); + do_print(OPTIONS, " %d %d [guest cpu, host pid]\n", cpu, pid); + } + +out: + free(buf); +} + static void dump_options(int fd) { unsigned short option; @@ -468,6 +527,9 @@ static void dump_options(int fd) case TRACECMD_OPTION_TIME_SHIFT: dump_option_timeshift(fd, size); break; + case TRACECMD_OPTION_GUEST: + dump_option_guest(fd, size); + break; default: do_print(OPTIONS, " %d %d\t[Unknown option, size - skipping]\n", option, size); diff --git a/tracecmd/trace-record.c b/tracecmd/trace-record.c index 7427fea4..5f799908 100644 --- a/tracecmd/trace-record.c +++ b/tracecmd/trace-record.c @@ -3059,6 +3059,19 @@ static int set_vcpu_pid_mapping(struct guest *guest, int cpu, int pid) return 0; } +static struct guest *get_guest_info(unsigned int guest_cid) +{ + int i; + + if (!guests) + return NULL; + + for (i = 0; i < guests_len; i++) + if (guest_cid == guests[i].cid) + return guests + i; + return NULL; +} + static char *get_qemu_guest_name(char *arg) { char *tok, *end = arg; @@ -3867,6 +3880,49 @@ static void append_buffer(struct tracecmd_output *handle, } } +static void +add_guest_info(struct tracecmd_output *handle, struct buffer_instance *instance) +{ + struct guest *guest = get_guest_info(instance->cid); + char *buf, *p; + int size; + int i; + + if (!guest) + return; + for (i = 0; i < guest->cpu_max; i++) + if (!guest->cpu_pid[i]) + break; + + size = strlen(guest->name) + 1; + size += sizeof(long long); /* trace_id */ + size += sizeof(int); /* cpu count */ + size += i * 2 * sizeof(int); /* cpu,pid pair */ + + buf = calloc(1, size); + if (!buf) + return; + p = buf; + strcpy(p, guest->name); + p += strlen(guest->name) + 1; + + memcpy(p, &instance->trace_id, sizeof(long long)); + p += sizeof(long long); + + memcpy(p, &i, sizeof(int)); + p += sizeof(int); + for (i = 0; i < guest->cpu_max; i++) { + if (!guest->cpu_pid[i]) + break; + memcpy(p, &i, sizeof(int)); + p += sizeof(int); + memcpy(p, &guest->cpu_pid[i], sizeof(int)); + p += sizeof(int); + } + + tracecmd_add_option(handle, TRACECMD_OPTION_GUEST, size, buf); + free(buf); +} static void add_pid_maps(struct tracecmd_output *handle, struct buffer_instance *instance) @@ -4151,6 +4207,11 @@ static void record_data(struct common_record_context *ctx) add_pid_maps(handle, instance); } + for_all_instances(instance) { + if (is_guest(instance)) + add_guest_info(handle, instance); + } + tracecmd_append_cpu_data(handle, local_cpu_count, temp_files); for (i = 0; i < max_cpu_count; i++) From patchwork Thu Feb 27 14:19:57 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: "Tzvetomir Stoyanov (VMware)" X-Patchwork-Id: 11408699 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 73DB7930 for ; Thu, 27 Feb 2020 14:20:23 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.kernel.org (Postfix) with ESMTP id 52DCA246AD for ; Thu, 27 Feb 2020 14:20:23 +0000 (UTC) Authentication-Results: mail.kernel.org; dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b="UKM0ijk7" Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S2389821AbgB0OUV (ORCPT ); Thu, 27 Feb 2020 09:20:21 -0500 Received: from mail-lf1-f67.google.com ([209.85.167.67]:33630 "EHLO mail-lf1-f67.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S2389728AbgB0OUU (ORCPT ); Thu, 27 Feb 2020 09:20:20 -0500 Received: by mail-lf1-f67.google.com with SMTP id n25so2233487lfl.0 for ; Thu, 27 Feb 2020 06:20:19 -0800 (PST) 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=AvccRY29WAE6SEpT6cihqrMVaq3y+rDhD0g13g/YdTY=; b=UKM0ijk76+AZNLXNqVyMXXsGhQByNSNUl1i95OJgBbEh8bC3A7djyZD1VV+CzcHjXW tXhaE6cf3RMnyR1x7iGHVKGRacz8sMmr65HieJMpKTLm/9/KsyW35+f8XQ5xxfWnAyF3 MmaG8LBPOYryfjYayUQRcZXGjKdCnuxGCj/xl9395JgFVlxG2Znf0TNyg7TQ4SE6heq8 xAso1DOrml6/Jz4tM37GmrqKj8cwXMIsorqkn/kceFm4w0AA9VPC12lETnXkj76gBU8A tfVq7o6+WUO4AP+l30L4GdoyC6tGVhn/uc4Q5R/su1IxUTnqJFZvEjI4bp48J+m6PDSw ALhg== 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=AvccRY29WAE6SEpT6cihqrMVaq3y+rDhD0g13g/YdTY=; b=iXy6Cur/tr7kNI1sBTXBjL8NwM+SNRt+i9Ji0XSwCcG13Kf0pDbcGI2+7ZmentmPDC ADRR5Ndd3+djeyRMjqtjV/Hp7k08JpUuROPPWErEyZvUeocrH6hxzqG6b2bBN4M+AQQk uJCzSn9Gxa9SeLMvcCsld9KklVUwFf9cTX9+CGjSheK27Y2HAi0n7uao2Kl0EFEaGr2p 0nV7e3htHLzyWcZNPHRAzn4xORqrY0P4PX4arma4AzuVhbX2CCGqHowj8BR7z/qmxQPQ HBrj3yAvnPitLlzR2CPHox26e8XKoebceMLCxMVHTHMXTFy43u6rDYLIBE5hiDpMTrwz k9IA== X-Gm-Message-State: ANhLgQ3q2a9r311mYwn0A16DG9fW5Z+JsVMbSyVwziGGmUSKvXfuJpWv 8STyU6l79t4cCORUohvwsAU= X-Google-Smtp-Source: ADFU+vvFh0SIcZXfq1Gcn3jCrwj+HncSlXSR/whWVqZIY452NMMLwoczsxfbT/09tZf4Rl1ckrexog== X-Received: by 2002:a19:8585:: with SMTP id h127mr2290681lfd.196.1582813218830; Thu, 27 Feb 2020 06:20:18 -0800 (PST) Received: from oberon.zico.biz ([83.222.187.186]) by smtp.gmail.com with ESMTPSA id l3sm3306437lja.78.2020.02.27.06.20.17 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Thu, 27 Feb 2020 06:20:18 -0800 (PST) From: "Tzvetomir Stoyanov (VMware)" To: rostedt@goodmis.org Cc: linux-trace-devel@vger.kernel.org Subject: [PATCH v20 11/15] trace-cmd: Add host trace clock as guest trace argument Date: Thu, 27 Feb 2020 16:19:57 +0200 Message-Id: <20200227142001.61577-12-tz.stoyanov@gmail.com> X-Mailer: git-send-email 2.24.1 In-Reply-To: <20200227142001.61577-1-tz.stoyanov@gmail.com> References: <20200227142001.61577-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 When tracing host and guest machines, both should use the same tracing clock for event timestamps. If a clock is specified as host tracing argument, with option "-C clock_name", the same is injected as guest tracing argument. If the user wants to use different tracing clocks, it can specify it using "-C clock_name" as guest tracing argument. In that case, the one specified by the user has higher priority. Signed-off-by: Tzvetomir Stoyanov (VMware) --- tracecmd/include/trace-local.h | 1 + tracecmd/trace-record.c | 21 +++++++++++++++++++++ 2 files changed, 22 insertions(+) diff --git a/tracecmd/include/trace-local.h b/tracecmd/include/trace-local.h index 4f2b5541..dc934f28 100644 --- a/tracecmd/include/trace-local.h +++ b/tracecmd/include/trace-local.h @@ -167,6 +167,7 @@ enum buffer_instance_flags { BUFFER_FL_PROFILE = 1 << 1, BUFFER_FL_GUEST = 1 << 2, BUFFER_FL_AGENT = 1 << 3, + BUFFER_FL_HAS_CLOCK = 1 << 4, }; struct func_list { diff --git a/tracecmd/trace-record.c b/tracecmd/trace-record.c index 5f799908..ee27cf0f 100644 --- a/tracecmd/trace-record.c +++ b/tracecmd/trace-record.c @@ -5555,6 +5555,8 @@ static void parse_record_options(int argc, char *sav; int name_counter = 0; int neg_event = 0; + struct buffer_instance *instance; + bool guest_sync_set = false; init_common_record_context(ctx, curr_cmd); @@ -5598,6 +5600,8 @@ static void parse_record_options(int argc, */ if (c != 'B' && c != 'A' && is_guest(ctx->instance)) { add_arg(ctx->instance, c, opts, long_options, optarg); + if (c == 'C') + ctx->instance->flags |= BUFFER_FL_HAS_CLOCK; continue; } @@ -5712,6 +5716,9 @@ static void parse_record_options(int argc, break; case 'C': ctx->instance->clock = optarg; + ctx->instance->flags |= BUFFER_FL_HAS_CLOCK; + if (is_top_instance(ctx->instance)) + guest_sync_set = true; break; case 'v': neg_event = 1; @@ -5936,6 +5943,20 @@ static void parse_record_options(int argc, add_argv(instance, "--date", true); } } + if (guest_sync_set) { + /* If -C is specified, prepend clock to all guest VM flags */ + for_all_instances(instance) { + if (top_instance.clock) { + if (is_guest(instance) && + !(instance->flags & BUFFER_FL_HAS_CLOCK)) { + add_argv(instance, + (char *)top_instance.clock, + true); + add_argv(instance, "-C", true); + } + } + } + } if (!ctx->filtered && ctx->instance->filter_mod) add_func(&ctx->instance->filter_funcs, From patchwork Thu Feb 27 14:19:58 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: "Tzvetomir Stoyanov (VMware)" X-Patchwork-Id: 11408701 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 C34CF92A for ; Thu, 27 Feb 2020 14:20:25 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.kernel.org (Postfix) with ESMTP id 98AD8246AC for ; Thu, 27 Feb 2020 14:20:25 +0000 (UTC) Authentication-Results: mail.kernel.org; dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b="ui+19ehD" Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S2389828AbgB0OUX (ORCPT ); Thu, 27 Feb 2020 09:20:23 -0500 Received: from mail-lf1-f67.google.com ([209.85.167.67]:33834 "EHLO mail-lf1-f67.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S2389286AbgB0OUW (ORCPT ); Thu, 27 Feb 2020 09:20:22 -0500 Received: by mail-lf1-f67.google.com with SMTP id w27so679915lfc.1 for ; Thu, 27 Feb 2020 06:20:20 -0800 (PST) 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=clFj0GUm3KZJiSDld7UwSf9wg4rUBmQulJxODCDRlvA=; b=ui+19ehDpw0k+0pZtcwfLJilTSGTPCYYKU29/xKLo+26ty+rQi7eYDXJwG4BqDvKBR O77HsUxtfRWX8+Ku1dOd6V/ukW1TxVsOCpf7jvIKFfK3eppiI1f3Y/XZaGomanR/8YdZ 3hcGu07j9R3Z+iZ0xJl/hfJpMB1I+koYNOBerFUyDGA5SzYV5ImJLL/jbXr5Z5XdmSHb fgROV7j2jpCeUtywIHwkuaV2YnL0dM5DrTg43Q7O+zhz+LYlLBuxCLh7hf/avaCuemv/ D/9E6z41zSv3UAjqu0fz3KBkp0z50NZoG/i93ZD9kmr3SyZ3B0QTQyrWFDM+9774tLRC wxlw== 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=clFj0GUm3KZJiSDld7UwSf9wg4rUBmQulJxODCDRlvA=; b=H6A21RNstEcIxmqPw6HbFhFyUhIqyUrwznSmZ8L2Y5rSgS/3H6oIYuzCfEJS6j1nA4 rexs6S9Id4P/1IXlHHy+nU/gMRxabDuUlcIEjHdGGKMkX6JcyK2/IOo/YGVULpWjKPMa 2XNT/PSsoyOqQHb1oYKa9Tbc89gi2B43kIDxrTQ5zg0vd/CL1mAmILjVUf/sa5vDxExo YGQ7ldFluld7Qj0JgYmRn0A+v1UOiupBstGS30OiAWtD9+LkgQqeNLlM2Fr7YIMyCM8Q 1o1dc3k6nZBTZihSgQPlAU6W8x1VUW8jJcIFqaRDMl7RbyJZIpYt34HSDOiDBJK02kqu KCzg== X-Gm-Message-State: ANhLgQ3l0JBjtDFKrN0azsoifytEMNkw/ewOksNlVlaA6q8gyMLRtvwm CfPzlOCtp8OqObzWqn0IEnw= X-Google-Smtp-Source: ADFU+vtPkVXtPuAFey3FbTh0Pxye0KIZYm9N/nhu/QVuay3nNbYwmWome9YU5kTpMHKTV78Owq+fSg== X-Received: by 2002:ac2:4246:: with SMTP id m6mr2331160lfl.165.1582813220146; Thu, 27 Feb 2020 06:20:20 -0800 (PST) Received: from oberon.zico.biz ([83.222.187.186]) by smtp.gmail.com with ESMTPSA id l3sm3306437lja.78.2020.02.27.06.20.18 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Thu, 27 Feb 2020 06:20:19 -0800 (PST) From: "Tzvetomir Stoyanov (VMware)" To: rostedt@goodmis.org Cc: linux-trace-devel@vger.kernel.org Subject: [PATCH v20 12/15] trace-cmd: Refactor few trace-cmd internal functions. Date: Thu, 27 Feb 2020 16:19:58 +0200 Message-Id: <20200227142001.61577-13-tz.stoyanov@gmail.com> X-Mailer: git-send-email 2.24.1 In-Reply-To: <20200227142001.61577-1-tz.stoyanov@gmail.com> References: <20200227142001.61577-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 In order to reuse code inside trace-cmd application context, few functions are made non static and "trace_" is prepended to their names: int trace_make_vsock(unsigned int port); int trace_get_vsock_port(int sd, unsigned int *port); int trace_open_vsock(unsigned int cid, unsigned int port); char *trace_get_guest_file(const char *file, const char *guest); Signed-off-by: Tzvetomir Stoyanov (VMware) --- tracecmd/include/trace-local.h | 6 ++++++ tracecmd/trace-agent.c | 10 +++++----- tracecmd/trace-record.c | 18 +++++++++--------- 3 files changed, 20 insertions(+), 14 deletions(-) diff --git a/tracecmd/include/trace-local.h b/tracecmd/include/trace-local.h index dc934f28..95d0026b 100644 --- a/tracecmd/include/trace-local.h +++ b/tracecmd/include/trace-local.h @@ -263,6 +263,12 @@ void tracecmd_disable_tracing(void); void tracecmd_enable_tracing(void); void tracecmd_stat_cpu(struct trace_seq *s, int cpu); +int trace_make_vsock(unsigned int port); +int trace_get_vsock_port(int sd, unsigned int *port); +int trace_open_vsock(unsigned int cid, unsigned int port); + +char *trace_get_guest_file(const char *file, const char *guest); + /* 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-agent.c b/tracecmd/trace-agent.c index 52d27195..a8ef0852 100644 --- a/tracecmd/trace-agent.c +++ b/tracecmd/trace-agent.c @@ -40,7 +40,7 @@ static int get_local_cid(unsigned int *cid) return ret; } -static int make_vsock(unsigned int port) +int trace_make_vsock(unsigned int port) { struct sockaddr_vm addr = { .svm_family = AF_VSOCK, @@ -64,7 +64,7 @@ static int make_vsock(unsigned int port) return sd; } -static int get_vsock_port(int sd, unsigned int *port) +int trace_get_vsock_port(int sd, unsigned int *port) { struct sockaddr_vm addr; socklen_t addr_len = sizeof(addr); @@ -87,11 +87,11 @@ static void make_vsocks(int nr, int *fds, unsigned int *ports) int i, fd, ret; for (i = 0; i < nr; i++) { - fd = make_vsock(VMADDR_PORT_ANY); + fd = trace_make_vsock(VMADDR_PORT_ANY); if (fd < 0) die("Failed to open vsocket"); - ret = get_vsock_port(fd, &port); + ret = trace_get_vsock_port(fd, &port); if (ret < 0) die("Failed to get vsocket address"); @@ -210,7 +210,7 @@ static void agent_serve(unsigned int port) nr_cpus = tracecmd_count_cpus(); page_size = getpagesize(); - sd = make_vsock(port); + sd = trace_make_vsock(port); if (sd < 0) die("Failed to open vsocket"); diff --git a/tracecmd/trace-record.c b/tracecmd/trace-record.c index ee27cf0f..30ba5bb2 100644 --- a/tracecmd/trace-record.c +++ b/tracecmd/trace-record.c @@ -537,7 +537,7 @@ static char *get_temp_file(struct buffer_instance *instance, int cpu) return file; } -static char *get_guest_file(const char *file, const char *guest) +char *trace_get_guest_file(const char *file, const char *guest) { const char *p; char *out = NULL; @@ -2930,7 +2930,7 @@ static int connect_port(const char *host, unsigned int port) } #ifdef VSOCK -static int open_vsock(unsigned int cid, unsigned int port) +int trace_open_vsock(unsigned int cid, unsigned int port) { struct sockaddr_vm addr = { .svm_family = AF_VSOCK, @@ -2993,7 +2993,7 @@ static bool can_splice_read_vsock(void) } #else -static inline int open_vsock(unsigned int cid, unsigned int port) +int trace_open_vsock(unsigned int cid, unsigned int port) { die("vsock is not supported"); return -1; @@ -3297,7 +3297,7 @@ create_recorder_instance(struct buffer_instance *instance, const char *file, int if (instance->use_fifos) fd = instance->fds[cpu]; else - fd = open_vsock(instance->cid, instance->client_ports[cpu]); + fd = trace_open_vsock(instance->cid, instance->client_ports[cpu]); if (fd < 0) die("Failed to connect to agent"); @@ -3689,7 +3689,7 @@ static void connect_to_agent(struct buffer_instance *instance) use_fifos = nr_fifos > 0; } - sd = open_vsock(instance->cid, instance->port); + sd = trace_open_vsock(instance->cid, instance->port); if (sd < 0) die("Failed to connect to vsocket @%u:%u", instance->cid, instance->port); @@ -3740,8 +3740,8 @@ static void setup_guest(struct buffer_instance *instance) int fd; /* Create a place to store the guest meta data */ - file = get_guest_file(output_file, - tracefs_instance_get_name(instance->tracefs)); + file = trace_get_guest_file(output_file, + tracefs_instance_get_name(instance->tracefs)); if (!file) die("Failed to allocate memory"); @@ -4077,8 +4077,8 @@ static void write_guest_file(struct buffer_instance *instance) char **temp_files; int i, fd; - file = get_guest_file(output_file, - tracefs_instance_get_name(instance->tracefs)); + file = trace_get_guest_file(output_file, + tracefs_instance_get_name(instance->tracefs)); if (!file) die("Failed to allocate memory"); From patchwork Thu Feb 27 14:19:59 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: "Tzvetomir Stoyanov (VMware)" X-Patchwork-Id: 11408703 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 75AE692A for ; Thu, 27 Feb 2020 14:20:29 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.kernel.org (Postfix) with ESMTP id 26BA3246A0 for ; Thu, 27 Feb 2020 14:20:29 +0000 (UTC) Authentication-Results: mail.kernel.org; dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b="S1ylRZJH" Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S2389900AbgB0OU2 (ORCPT ); Thu, 27 Feb 2020 09:20:28 -0500 Received: from mail-lj1-f193.google.com ([209.85.208.193]:43836 "EHLO mail-lj1-f193.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S2389876AbgB0OU1 (ORCPT ); Thu, 27 Feb 2020 09:20:27 -0500 Received: by mail-lj1-f193.google.com with SMTP id e3so3584927lja.10 for ; Thu, 27 Feb 2020 06:20:23 -0800 (PST) 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=La35HO2xQnZG8AwtmhKR7btx0xR0kD55tc3ooMym7JU=; b=S1ylRZJHjn+wzUKVdlvuFxuXfQ9HSdu+W4HOgw4RxUFo7e2MTEEkc9DtiV5NzmRhXv FKV8oEcMNSdYWD1xGXCqoZgFG7vnIZYrcF3CWx0ZOgYgUpysOUc90EAD/cyzGKVxKPa5 23X3OsjxehVkUDvQ+6obI3/AqaU/WvWtzM5LbYqCjZbX3c5lkzhjCuInjjZKyOfdozL+ NnA6GCaxsKmqzs5dlDHLQwX8Hck41O/sjt3rPVDeuoTbcHHrkbb/MNRdwf1+j0DC4WH2 0VomBnITA3cURUEgMS7GyqYDYfesnUA+a9+pLOkYrjnLqgJK4QcRsLkNKnG+JYCcqg9d Ffgg== 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=La35HO2xQnZG8AwtmhKR7btx0xR0kD55tc3ooMym7JU=; b=VEqDHwxW8a3NfcBh/sBy89+WkqvVsJ4gXKJId0Hx6wtpmuUnGUU1huPkR1O5y42iKu WsrBG3Ei+y8Xo+6LrGs+xS1bwwI96DTHiU1rfMg1LZcR7wBSgHTSIFFDADCZelvuH3hp ZTDHmqh2MT2e5tEgyrwPEEgQ716wh+o0grdNXO07DPQACGLyTFrZnm7ZQxzWKxVsstTN EB5CQ2ed9typGbSrWCBwl+5ueYffA1n9WuvjtEn9waUsIpy7QiGV+ujCXeOvmyqLok3J HuCf/x9WZfkk4hWmDM4GhPDHmFymBgXbmOS12BrHvf0YZFgqAhhAbvjp38afbWYQ8TzL OyFg== X-Gm-Message-State: ANhLgQ1WSuQTQjeKxXzQQb+fZjrmVCEvcI30yqQcfHkPrS8IhoctsvW7 QzMWAHTrEGlA/U+0jmjNcFc= X-Google-Smtp-Source: ADFU+vvhqCk1Ri0YU0d5JweB6g21mrB80dGaxqVTO165lorlRSLBc4Dm4h730nIznn+hUApI6XBgWw== X-Received: by 2002:a2e:e12:: with SMTP id 18mr3088022ljo.123.1582813222091; Thu, 27 Feb 2020 06:20:22 -0800 (PST) Received: from oberon.zico.biz ([83.222.187.186]) by smtp.gmail.com with ESMTPSA id l3sm3306437lja.78.2020.02.27.06.20.20 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Thu, 27 Feb 2020 06:20:21 -0800 (PST) From: "Tzvetomir Stoyanov (VMware)" To: rostedt@goodmis.org Cc: linux-trace-devel@vger.kernel.org Subject: [PATCH v20 13/15] trace-cmd: Basic infrastructure for host - guest timestamp synchronization Date: Thu, 27 Feb 2020 16:19:59 +0200 Message-Id: <20200227142001.61577-14-tz.stoyanov@gmail.com> X-Mailer: git-send-email 2.24.1 In-Reply-To: <20200227142001.61577-1-tz.stoyanov@gmail.com> References: <20200227142001.61577-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 The infrastructure for host - guest timestamp synchronization is divided in two parts: - logic in libtracecmd - logic in trace-cmd application The libtracecmd is extended with new trace message, MSG_TIME_SYNC, used to exchange time synch information between host and guest. The trace request and response messages are extended to handle the time synch negotiation. The logic is implemented in trace-timesync.c file: - Register / unregister time sync protocols. - Choosing what protocol will be used for a tracing session. - Init common context, used by all protocols - a ftrace instance, vsockets. - Invoke protocol routines to perform time synchronization. - Store calculated offsets in an array. The trace-cmd application is extended to perform timestamp synchronization. The main logic is in trace-tsync.c file - Negotiate what time synch algorithm will be used for the tracing session. - Run pthreads, to do continuous timestamp synchronization, during the trace. - Store calculated offsets in guest's trace.dat file, using TRACECMD_OPTION_TIME_SHIFT option - A new trace-cmd option is added, to control the timestamp synchronization: --tsync-interval: set the time sync loop interval, in ms. The default value is 0 - timestamp synchronization is performed twice, before and after the trace. If a negative number is specified, the timestamp synchronization is disabled. Signed-off-by: Tzvetomir Stoyanov (VMware) --- Documentation/trace-cmd-record.1.txt | 7 + include/trace-cmd/trace-cmd.h | 58 ++- lib/trace-cmd/Makefile | 1 + lib/trace-cmd/include/trace-tsync-local.h | 38 ++ lib/trace-cmd/trace-msg.c | 395 ++++++++++++++--- lib/trace-cmd/trace-timesync.c | 498 ++++++++++++++++++++++ tracecmd/Makefile | 3 +- tracecmd/include/trace-local.h | 11 + tracecmd/trace-agent.c | 39 +- tracecmd/trace-record.c | 40 +- tracecmd/trace-tsync.c | 272 ++++++++++++ tracecmd/trace-usage.c | 4 + 12 files changed, 1299 insertions(+), 67 deletions(-) create mode 100644 lib/trace-cmd/include/trace-tsync-local.h create mode 100644 lib/trace-cmd/trace-timesync.c create mode 100644 tracecmd/trace-tsync.c diff --git a/Documentation/trace-cmd-record.1.txt b/Documentation/trace-cmd-record.1.txt index 0d75e43d..f5ecad5c 100644 --- a/Documentation/trace-cmd-record.1.txt +++ b/Documentation/trace-cmd-record.1.txt @@ -338,6 +338,13 @@ OPTIONS the offset will also be in nanoseconds even if the displayed units are in microseconds. +*--tsync-interval*:: + Set the loop interval, in ms, for timestamps synchronization with guests: + If a negative number is specified, timestamps synchronization is disabled + If 0 is specified, no loop is performed - timestamps offset is calculated only twice," + at the beginning and at the end of the trace. + Timestamps synchronization with guests works only if there is support for VSOCK.\n" + *--stderr*:: Have output go to stderr instead of stdout, but the output of the command executed will not be changed. This is useful if you want to monitor the diff --git a/include/trace-cmd/trace-cmd.h b/include/trace-cmd/trace-cmd.h index 0375f500..42b47e2f 100644 --- a/include/trace-cmd/trace-cmd.h +++ b/include/trace-cmd/trace-cmd.h @@ -379,19 +379,69 @@ 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, - unsigned long long trace_id); + unsigned long long trace_id, + char *tsync_protos, + int tsync_protos_size); int tracecmd_msg_recv_trace_req(struct tracecmd_msg_handle *msg_handle, int *argc, char ***argv, bool *use_fifos, - unsigned long long *trace_id); + unsigned long long *trace_id, + char **tsync_protos, + unsigned int *tsync_protos_size); 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 long long trace_id); + unsigned long long trace_id, + unsigned int tsync_proto, + unsigned int tsync_port); 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 long long *trace_id); + unsigned long long *trace_id, + unsigned int *tsync_proto, + unsigned int *tsync_port); + +int tracecmd_msg_send_time_sync(struct tracecmd_msg_handle *msg_handle, + unsigned int sync_protocol, + unsigned int sync_msg_id, + unsigned int payload_size, char *payload); +int tracecmd_msg_recv_time_sync(struct tracecmd_msg_handle *msg_handle, + unsigned int *sync_protocol, + unsigned int *sync_msg_id, + unsigned int *payload_size, char **payload); + +/* --- Timestamp synchronization --- */ + +enum{ + TRACECMD_TIME_SYNC_PROTO_NONE = 0, +}; +enum{ + TRACECMD_TIME_SYNC_CMD_PROBE = 1, + TRACECMD_TIME_SYNC_CMD_STOP = 2, +}; + +#define TRACECMD_TIME_SYNC_PROTO_PTP_WEIGHT 10 + +struct tracecmd_time_sync { + unsigned int sync_proto; + int loop_interval; + pthread_mutex_t lock; + pthread_cond_t cond; + char *clock_str; + struct tracecmd_msg_handle *msg_handle; + void *context; +}; + +void tracecmd_tsync_init(void); +int tracecmd_tsync_proto_getall(char **proto_mask, int *words); +unsigned int tracecmd_tsync_proto_select(char *proto_mask, int words); +bool tsync_proto_is_supported(unsigned int proto_id); +void tracecmd_tsync_with_host(struct tracecmd_time_sync *tsync); +void tracecmd_tsync_with_guest(struct tracecmd_time_sync *tsync); +int tracecmd_tsync_get_offsets(struct tracecmd_time_sync *tsync, + int *count, + long long **ts, long long **offsets); +void tracecmd_tsync_free(struct tracecmd_time_sync *tsync); /* --- Plugin handling --- */ extern struct tep_plugin_option trace_ftrace_options[]; diff --git a/lib/trace-cmd/Makefile b/lib/trace-cmd/Makefile index 29c36ca1..ab7440ac 100644 --- a/lib/trace-cmd/Makefile +++ b/lib/trace-cmd/Makefile @@ -16,6 +16,7 @@ OBJS += trace-util.o OBJS += trace-filter-hash.o OBJS += trace-msg.o OBJS += trace-plugin.o +OBJS += trace-timesync.o # Additional util objects OBJS += trace-blk-hack.o diff --git a/lib/trace-cmd/include/trace-tsync-local.h b/lib/trace-cmd/include/trace-tsync-local.h new file mode 100644 index 00000000..1de9d5e5 --- /dev/null +++ b/lib/trace-cmd/include/trace-tsync-local.h @@ -0,0 +1,38 @@ +/* SPDX-License-Identifier: LGPL-2.1 */ +/* + * Copyright (C) 2019, VMware, Tzvetomir Stoyanov + * + */ +#ifndef _TRACE_TSYNC_LOCAL_H +#define _TRACE_TSYNC_LOCAL_H + +#include + +struct clock_sync_context { + void *proto_data; /* time sync protocol specific data */ + bool is_server; /* server side time sync role */ + struct tracefs_instance *instance; /* ftrace buffer, used for time sync events */ + + /* Arrays with calculated time offsets at given time */ + int sync_size; /* Allocated size of sync_ts and sync_offsets */ + int sync_count; /* Number of elements in sync_ts and sync_offsets */ + long long *sync_ts; + long long *sync_offsets; + + /* Identifiers of local and remote time sync peers: cid and port */ + unsigned int local_cid; + unsigned int local_port; + unsigned int remote_cid; + unsigned int remote_port; +}; + +int tracecmd_tsync_proto_register(unsigned int proto_id, int weight, + int (*init)(struct tracecmd_time_sync *), + int (*free)(struct tracecmd_time_sync *), + int (*calc)(struct tracecmd_time_sync *, + long long *, long long *)); +int tracecmd_tsync_proto_unregister(unsigned int proto_id); + +int ptp_clock_sync_register(void); + +#endif /* _TRACE_TSYNC_LOCAL_H */ diff --git a/lib/trace-cmd/trace-msg.c b/lib/trace-cmd/trace-msg.c index d6a68ac3..5a00dbf2 100644 --- a/lib/trace-cmd/trace-msg.c +++ b/lib/trace-cmd/trace-msg.c @@ -29,6 +29,8 @@ typedef __u32 u32; typedef __be32 be32; +typedef __u64 u64; +typedef __s64 s64; static inline void dprint(const char *fmt, ...) { @@ -61,6 +63,18 @@ struct tracecmd_msg_rinit { be32 cpus; } __attribute__((packed)); +#define TRACE_REQ_PARAM_SIZE (2 * sizeof(int)) +enum trace_req_params { + TRACE_REQUEST_ARGS, + TRACE_REQUEST_TSYNC_PROTOS, +}; + +struct tracecmd_msg_trace_req_param { + int id; + int length; + char *value; +}; + struct tracecmd_msg_trace_req { be32 flags; be32 argc; @@ -72,6 +86,13 @@ struct tracecmd_msg_trace_resp { be32 cpus; be32 page_size; u64 trace_id; + be32 tsync_proto; + be32 tsync_port; +} __attribute__((packed)); + +struct tracecmd_msg_tsync { + be32 sync_protocol; + be32 sync_msg_id; } __attribute__((packed)); struct tracecmd_msg_header { @@ -89,7 +110,8 @@ struct tracecmd_msg_header { 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_RESP, 8, 0), \ + C(TIME_SYNC, 9, sizeof(struct tracecmd_msg_tsync)), #undef C #define C(a,b,c) MSG_##a = b @@ -123,6 +145,7 @@ struct tracecmd_msg { struct tracecmd_msg_rinit rinit; struct tracecmd_msg_trace_req trace_req; struct tracecmd_msg_trace_resp trace_resp; + struct tracecmd_msg_tsync tsync; }; char *buf; } __attribute__((packed)); @@ -265,6 +288,17 @@ static int tracecmd_msg_send(int fd, struct tracecmd_msg *msg) return ret; } +static int msg_send_nofree(int fd, struct tracecmd_msg *msg) +{ + int ret = 0; + + ret = msg_write(fd, msg); + if (ret < 0) + ret = -ECOMM; + + return ret; +} + static int msg_read(int fd, void *buf, u32 size, int *n) { ssize_t r; @@ -814,81 +848,141 @@ 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, unsigned long long trace_id) +static int make_trace_req_protos(char **buf, int *size, + int protos_size, char *tsync_protos) { - size_t args_size = 0; + size_t buf_size; + char *nbuf; + char *p; + + buf_size = TRACE_REQ_PARAM_SIZE + protos_size; + nbuf = realloc(*buf, *size + buf_size); + if (!nbuf) + return -1; + + p = nbuf + *size; + memset(p, 0, buf_size); + + *(unsigned int *)p = htonl(TRACE_REQUEST_TSYNC_PROTOS); + p += sizeof(int); + *(unsigned int *)p = htonl(protos_size); + p += sizeof(int); + + memcpy(p, tsync_protos, protos_size); + + *size += buf_size; + *buf = nbuf; + return 0; +} + +static int make_trace_req_args(char **buf, int *size, int argc, char **argv) +{ + size_t args_size; + size_t buf_size; + char *nbuf; char *p; int i; + args_size = sizeof(int); for (i = 0; i < argc; i++) 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.argc = htonl(argc); - msg->trace_req.trace_id = htonll(trace_id); - msg->buf = calloc(args_size, 1); - if (!msg->buf) - return -ENOMEM; + buf_size = TRACE_REQ_PARAM_SIZE + args_size; + nbuf = realloc(*buf, *size + buf_size); + if (!nbuf) + return -1; + + p = nbuf + *size; + memset(p, 0, buf_size); + + *(unsigned int *)p = htonl(TRACE_REQUEST_ARGS); + p += sizeof(int); + *(unsigned int *)p = htonl(args_size); + p += sizeof(int); - p = msg->buf; + *(unsigned int *)p = htonl(argc); + p += sizeof(int); for (i = 0; i < argc; i++) p = stpcpy(p, argv[i]) + 1; + *size += buf_size; + *buf = nbuf; + return 0; +} + +static int make_trace_req(struct tracecmd_msg *msg, int argc, char **argv, + bool use_fifos, unsigned long long trace_id, + char *tsync_protos, int tsync_protos_size) +{ + int size = 0; + char *buf = NULL; + + msg->trace_req.flags = 0; + if (use_fifos) + msg->trace_req.flags |= MSG_TRACE_USE_FIFOS; + msg->trace_req.flags = htonl(msg->trace_req.flags); + msg->trace_req.trace_id = htonll(trace_id); + + if (argc && argv) + make_trace_req_args(&buf, &size, argc, argv); + if (tsync_protos_size && tsync_protos) + make_trace_req_protos(&buf, &size, + tsync_protos_size, tsync_protos); + + msg->buf = buf; + msg->hdr.size = htonl(ntohl(msg->hdr.size) + size); + return 0; } int tracecmd_msg_send_trace_req(struct tracecmd_msg_handle *msg_handle, int argc, char **argv, bool use_fifos, - unsigned long long trace_id) + unsigned long long trace_id, + char *tsync_protos, + int tsync_protos_size) { struct tracecmd_msg msg; int ret; tracecmd_msg_init(MSG_TRACE_REQ, &msg); - ret = make_trace_req(&msg, argc, argv, use_fifos, trace_id); + ret = make_trace_req(&msg, argc, argv, use_fifos, + trace_id, tsync_protos, tsync_protos_size); if (ret < 0) return ret; return tracecmd_msg_send(msg_handle->fd, &msg); } - /* - * NOTE: On success, the returned `argv` should be freed with: - * free(argv[0]); - * free(argv); - */ -int tracecmd_msg_recv_trace_req(struct tracecmd_msg_handle *msg_handle, - int *argc, char ***argv, bool *use_fifos, - unsigned long long *trace_id) +static int get_trace_req_protos(char *buf, int length, + char **tsync_protos, + unsigned int *tsync_protos_size) { - struct tracecmd_msg msg; - char *p, *buf_end, **args; - int i, ret, nr_args; - ssize_t buf_len; + *tsync_protos = malloc(length); + if (!*tsync_protos) + return -1; + memcpy(*tsync_protos, buf, length); + *tsync_protos_size = length; - ret = tracecmd_msg_recv(msg_handle->fd, &msg); - if (ret < 0) - return ret; + return 0; +} - if (ntohl(msg.hdr.cmd) != MSG_TRACE_REQ) { - ret = -ENOTSUP; - goto out; - } +static int get_trace_req_args(char *buf, int length, int *argc, char ***argv) +{ + unsigned int nr_args; + char *p, *buf_end; + char **args = NULL; + char *vagrs = NULL; + int ret; + int i; - nr_args = ntohl(msg.trace_req.argc); - if (nr_args <= 0) { + if (length <= sizeof(int) || buf[length - 1] != '\0') { ret = -EINVAL; goto out; } - buf_len = ntohl(msg.hdr.size) - MSG_HDR_LEN - ntohl(msg.hdr.cmd_size); - buf_end = (char *)msg.buf + buf_len; - if (buf_len <= 0 && ((char *)msg.buf)[buf_len-1] != '\0') { - ret = -EINVAL; - goto out; - } + nr_args = ntohl(*(unsigned int *)buf); + buf += sizeof(int); + length -= sizeof(int); args = calloc(nr_args, sizeof(*args)); if (!args) { @@ -896,10 +990,18 @@ int tracecmd_msg_recv_trace_req(struct tracecmd_msg_handle *msg_handle, goto out; } - for (i = 0, p = msg.buf; i < nr_args; i++, p++) { + vagrs = calloc(length, sizeof(char)); + if (!vagrs) { + ret = -ENOMEM; + goto out; + } + + memcpy(vagrs, buf, length); + buf_end = vagrs + length; + for (i = 0, p = vagrs; i < nr_args; i++, p++) { if (p >= buf_end) { ret = -EINVAL; - goto out_args; + goto out; } args[i] = p; p = strchr(p, '\0'); @@ -907,18 +1009,82 @@ int tracecmd_msg_recv_trace_req(struct tracecmd_msg_handle *msg_handle, *argc = nr_args; *argv = args; + return 0; + +out: + free(args); + free(vagrs); + return ret; + +} + +/* + * NOTE: On success, the returned `argv` should be freed with: + * free(argv[0]); + * free(argv); + * and `tsync_protos` with free(tsync_protos); + */ +int tracecmd_msg_recv_trace_req(struct tracecmd_msg_handle *msg_handle, + int *argc, char ***argv, bool *use_fifos, + unsigned long long *trace_id, + char **tsync_protos, + unsigned int *tsync_protos_size) +{ + struct tracecmd_msg msg; + unsigned int param_id; + int param_length; + ssize_t buf_len; + char *p; + int ret; + + ret = tracecmd_msg_recv(msg_handle->fd, &msg); + if (ret < 0) + return ret; + + if (ntohl(msg.hdr.cmd) != MSG_TRACE_REQ) { + ret = -ENOTSUP; + goto out; + } + + buf_len = ntohl(msg.hdr.size) - MSG_HDR_LEN - ntohl(msg.hdr.cmd_size); + if (buf_len < 0) { + ret = -EINVAL; + goto out; + } + *use_fifos = ntohl(msg.trace_req.flags) & MSG_TRACE_USE_FIFOS; *trace_id = ntohll(msg.trace_req.trace_id); - /* - * On success we're passing msg.buf to the caller through argv[0] so we - * reset it here before calling msg_free(). - */ - msg.buf = NULL; + p = msg.buf; + while (buf_len > 2 * sizeof(int)) { + param_id = ntohl(*((unsigned int *)p)); + p += sizeof(int); + buf_len -= sizeof(int); + param_length = ntohl(*((unsigned int *)p)); + p += sizeof(int); + buf_len -= sizeof(int); + if (buf_len < param_length) + break; + ret = 0; + switch (param_id) { + case TRACE_REQUEST_ARGS: + ret = get_trace_req_args(p, param_length, argc, argv); + break; + case TRACE_REQUEST_TSYNC_PROTOS: + ret = get_trace_req_protos(p, param_length, + tsync_protos, tsync_protos_size); + break; + default: + break; + } + if (ret) + break; + buf_len -= param_length; + p += param_length; + } + msg_free(&msg); return 0; -out_args: - free(args); out: error_operation(&msg); if (ret == -EOPNOTSUPP) @@ -927,9 +1093,118 @@ out: return ret; } +/** + * tracecmd_msg_send_time_sync - Send a time sync packet + * @msg_handle: message handle, holding the communication context + * @sync_protocol: id of the time synch protocol + * @sync_msg_id: id if the time synch message, protocol dependent + * @payload_size: size of the packet payload, 0 in case of no payload + * @payload: pointer to the packet payload, or NULL in case of no payload + * + * Returns 0 if packet is sent successfully, or negative error otherwise. + */ +int tracecmd_msg_send_time_sync(struct tracecmd_msg_handle *msg_handle, + unsigned int sync_protocol, + unsigned int sync_msg_id, + unsigned int payload_size, char *payload) +{ + struct tracecmd_msg msg; + + tracecmd_msg_init(MSG_TIME_SYNC, &msg); + msg.tsync.sync_protocol = htonl(sync_protocol); + msg.tsync.sync_msg_id = htonl(sync_msg_id); + msg.hdr.size = htonl(ntohl(msg.hdr.size) + payload_size); + + msg.buf = payload; + return msg_send_nofree(msg_handle->fd, &msg); +} + +/** + * tracecmd_msg_recv_time_sync - Receive a time sync packet + * @msg_handle: message handle, holding the communication context + * @sync_protocol: return the id of the packet's time synch protocol + * @sync_msg_id: return the id of the packet's time synch message + * @payload_size: size of the packet's payload, can be: + * NULL - the payload is not interested and should be ignored + * pointer to int, with value 0 - update with the size of the payload + * allocate memory and cpy the payload + * into it + * pointer to int, with value greater than 0 - expected size of the + * payload, preallocated + * memory is passed to the API + * with that size + *@payload: pointer to the packet payload, can be: + * NULL - the payload is not interested and should be ignored + * pointer to char *, with value NULL - a new memory is allocated and returned + * here, containing the packet's payload + * the @payload_size is updated with the + * size of the allocated memory. It must be + * freed by free() + * pointer to char *, with no-NULL value - A prealocated array is passed, with size + * @payload_size. If payload's size is equal + * or less, it will be copied here. + * + * Returns 0 if packet is received successfully, or negative error otherwise. + */ +int tracecmd_msg_recv_time_sync(struct tracecmd_msg_handle *msg_handle, + unsigned int *sync_protocol, + unsigned int *sync_msg_id, + unsigned int *payload_size, char **payload) +{ + struct tracecmd_msg msg; + int ret = -1; + int buf_size; + + memset(&msg, 0, sizeof(msg)); + ret = tracecmd_msg_recv(msg_handle->fd, &msg); + if (ret < 0) + goto out; + + if (ntohl(msg.hdr.cmd) != MSG_TIME_SYNC) { + ret = -EOPNOTSUPP; + goto out; + } + + if (sync_protocol) + *sync_protocol = ntohl(msg.tsync.sync_protocol); + if (sync_msg_id) + *sync_msg_id = ntohl(msg.tsync.sync_msg_id); + + buf_size = msg_buf_len(&msg); + if (buf_size < 0) { + ret = -EINVAL; + goto out; + } + + if (buf_size && payload && payload_size) { + if (*payload_size) { + if (*payload_size < buf_size || *payload == NULL) { + ret = -ENOMEM; + goto out; + } + memcpy(*payload, msg.buf, buf_size); + goto out; + } + + *payload = malloc(buf_size); + if (*payload == NULL) { + ret = -ENOMEM; + goto out; + } + *payload_size = buf_size; + memcpy(*payload, msg.buf, buf_size); + } + +out: + msg_free(&msg); + return ret; +} + static int make_trace_resp(struct tracecmd_msg *msg, int page_size, int nr_cpus, unsigned int *ports, bool use_fifos, - unsigned long long trace_id) + unsigned long long trace_id, + unsigned int tsync_proto, + unsigned int tsync_port) { int data_size; @@ -940,7 +1215,11 @@ 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_req.flags = use_fifos ? htonl(MSG_TRACE_USE_FIFOS) : htonl(0); + msg->trace_resp.flags = htonl(msg->trace_resp.flags); + msg->trace_resp.tsync_proto = htonl(tsync_proto); + msg->trace_resp.tsync_port = htonl(tsync_port); + msg->trace_resp.cpus = htonl(nr_cpus); msg->trace_resp.page_size = htonl(page_size); msg->trace_resp.trace_id = htonll(trace_id); @@ -951,14 +1230,16 @@ 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 long long trace_id) + unsigned long long trace_id, + unsigned int tsync_proto, + unsigned int tsync_port) { 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, trace_id); + use_fifos, trace_id, tsync_proto, tsync_port); if (ret < 0) return ret; @@ -968,7 +1249,9 @@ 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 long long *trace_id) + unsigned long long *trace_id, + unsigned int *tsync_proto, + unsigned int *tsync_port) { struct tracecmd_msg msg; char *p, *buf_end; @@ -994,6 +1277,8 @@ int tracecmd_msg_recv_trace_resp(struct tracecmd_msg_handle *msg_handle, *nr_cpus = ntohl(msg.trace_resp.cpus); *page_size = ntohl(msg.trace_resp.page_size); *trace_id = ntohll(msg.trace_resp.trace_id); + *tsync_proto = ntohl(msg.trace_resp.tsync_proto); + *tsync_port = ntohl(msg.trace_resp.tsync_port); *ports = calloc(*nr_cpus, sizeof(**ports)); if (!*ports) { ret = -ENOMEM; diff --git a/lib/trace-cmd/trace-timesync.c b/lib/trace-cmd/trace-timesync.c new file mode 100644 index 00000000..0534b14f --- /dev/null +++ b/lib/trace-cmd/trace-timesync.c @@ -0,0 +1,498 @@ +// SPDX-License-Identifier: LGPL-2.1 +/* + * Copyright (C) 2019, VMware, Tzvetomir Stoyanov + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "trace-cmd.h" +#include "tracefs.h" +#include "event-utils.h" +#include "trace-tsync-local.h" + +struct tsync_proto { + struct tsync_proto *next; + unsigned int proto_id; + int weight; + + int (*clock_sync_init)(struct tracecmd_time_sync *clock_context); + int (*clock_sync_free)(struct tracecmd_time_sync *clock_context); + int (*clock_sync_calc)(struct tracecmd_time_sync *clock_context, + long long *offset, long long *timestamp); +}; + +static struct tsync_proto *tsync_proto_list; + +static struct tsync_proto *tsync_proto_find(unsigned int proto_id) +{ + struct tsync_proto *proto; + + for (proto = tsync_proto_list; proto; proto = proto->next) + if (proto->proto_id == proto_id) + return proto; + + return NULL; +} + +int tracecmd_tsync_proto_register(unsigned int proto_id, int weight, + int (*init)(struct tracecmd_time_sync *), + int (*free)(struct tracecmd_time_sync *), + int (*calc)(struct tracecmd_time_sync *, + long long *, long long *)) +{ + struct tsync_proto *proto; + + if (tsync_proto_find(proto_id)) + return -1; + proto = calloc(1, sizeof(struct tsync_proto)); + if (!proto) + return -1; + proto->proto_id = proto_id; + proto->weight = weight; + proto->clock_sync_init = init; + proto->clock_sync_free = free; + proto->clock_sync_calc = calc; + + proto->next = tsync_proto_list; + tsync_proto_list = proto; + return 0; +} + +int tracecmd_tsync_proto_unregister(unsigned int proto_id) +{ + struct tsync_proto **last = &tsync_proto_list; + + for (; *last; last = &(*last)->next) { + if ((*last)->proto_id == proto_id) { + struct tsync_proto *proto = *last; + + *last = proto->next; + free(proto); + return 0; + } + } + + return -1; +} + +bool tsync_proto_is_supported(unsigned int proto_id) +{ + if (tsync_proto_find(proto_id)) + return true; + return false; +} + +/** + * tracecmd_tsync_get_offsets - Return the calculated time offsets + * + * @tsync: Pointer to time sync context + * @count: Returns the number of calculated time offsets + * @ts: Array of size @count containing timestamps of callculated offsets + * @offsets: array of size @count, containing offsets for each timestamp + * + * Retuns -1 in case of an error, or 0 otherwise + */ +int tracecmd_tsync_get_offsets(struct tracecmd_time_sync *tsync, + int *count, + long long **ts, long long **offsets) +{ + struct clock_sync_context *tsync_context; + + if (!tsync || !tsync->context) + return -1; + tsync_context = (struct clock_sync_context *)tsync->context; + if (count) + *count = tsync_context->sync_count; + if (ts) + *ts = tsync_context->sync_ts; + if (offsets) + *offsets = tsync_context->sync_offsets; + return 0; +} + + +#define PROTO_MASK_SIZE (sizeof(char)) +/** + * tracecmd_tsync_proto_select - Select time sync protocol, to be used for + * timestamp synchronization with a peer + * + * @proto_mask: bitmask array of time sync protocols, supported by the peer + * @length: size of the @protos array + * + * Retuns Id of a time sync protocol, that can be used with the peer, or 0 + * in case there is no match with supported protocols + */ +unsigned int tracecmd_tsync_proto_select(char *proto_mask, int length) +{ + struct tsync_proto *selected = NULL; + struct tsync_proto *proto; + int word; + int id; + + for (word = 0; word < length; word++) { + for (proto = tsync_proto_list; proto; proto = proto->next) { + if (proto->proto_id < word * PROTO_MASK_SIZE) + continue; + + id = proto->proto_id - word * PROTO_MASK_SIZE; + if (id >= PROTO_MASK_SIZE) + continue; + + if ((1 << id) & proto_mask[word]) { + if (selected) { + if (selected->weight < proto->weight) + selected = proto; + } else + selected = proto; + } + } + } + + if (selected) + return selected->proto_id; + + return 0; +} + +/** + * tracecmd_tsync_proto_getall - Returns bitmask of all supported + * time sync protocols + * @proto_mask: return, allocated bitmask array of time sync protocols, + * supported by the peer. Must be freed by free() + * @words: return, allocated size of the @protobits array + * + * If completed successfully 0 is returned and allocated array in @proto_mask of + * size @words. In case of an error, -1 is returned. + * @proto_mask must be freed with free() + */ +int tracecmd_tsync_proto_getall(char **proto_mask, int *words) +{ + struct tsync_proto *proto; + int proto_max = 0; + int count = 0; + char *protos; + + for (proto = tsync_proto_list; proto; proto = proto->next) + if (proto->proto_id > proto_max) + proto_max = proto->proto_id; + + count = proto_max / PROTO_MASK_SIZE + 1; + protos = calloc(count, sizeof(char)); + if (!protos) + return -1; + + for (proto = tsync_proto_list; proto; proto = proto->next) { + if ((proto->proto_id / PROTO_MASK_SIZE) >= count) + continue; + protos[proto->proto_id / PROTO_MASK_SIZE] |= + (1 << (proto->proto_id % PROTO_MASK_SIZE)); + } + + *proto_mask = protos; + *words = count; + return 0; +} + +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; +} + +static struct tracefs_instance * +clock_synch_create_instance(const char *clock, unsigned int cid) +{ + struct tracefs_instance *instance; + char inst_name[256]; + + snprintf(inst_name, 256, "clock_synch-%d", cid); + + instance = tracefs_instance_alloc(inst_name); + if (!instance) + return NULL; + + tracefs_instance_create(instance); + tracefs_instance_file_write(instance, "trace", "\0"); + if (clock) + tracefs_instance_file_write(instance, "trace_clock", clock); + return instance; +} + +static void +clock_synch_delete_instance(struct tracefs_instance *inst) +{ + if (!inst) + return; + tracefs_instance_destroy(inst); + tracefs_instance_free(inst); +} + +static int clock_context_init(struct tracecmd_time_sync *tsync, bool server) +{ + struct clock_sync_context *clock = NULL; + struct tsync_proto *protocol; + + if (tsync->context) + return 0; + + protocol = tsync_proto_find(tsync->sync_proto); + if (!protocol) + return -1; + + clock = calloc(1, sizeof(struct clock_sync_context)); + if (!clock) + return -1; + + clock->is_server = server; + if (get_vsocket_params(tsync->msg_handle->fd, &clock->local_cid, + &clock->local_port, &clock->remote_cid, + &clock->remote_port)) + goto error; + + clock->instance = clock_synch_create_instance(tsync->clock_str, + clock->remote_cid); + if (!clock->instance) + goto error; + + tsync->context = clock; + if (protocol->clock_sync_init && protocol->clock_sync_init(tsync) < 0) + goto error; + + return 0; +error: + tsync->context = NULL; + free(clock); + return -1; +} + +/** + * tracecmd_tsync_free - Free time sync context, allocated by + * tracecmd_tsync_with_host() or tracecmd_tsync_with_guest() APIs + * + * @tsync: Pointer to time sync context + * + */ +void tracecmd_tsync_free(struct tracecmd_time_sync *tsync) +{ + struct clock_sync_context *tsync_context; + struct tsync_proto *proto; + + if (!tsync->context) + return; + tsync_context = (struct clock_sync_context *)tsync->context; + + proto = tsync_proto_find(tsync->sync_proto); + if (proto && proto->clock_sync_free) + proto->clock_sync_free(tsync); + + clock_synch_delete_instance(tsync_context->instance); + tsync_context->instance = NULL; + + free(tsync_context->sync_ts); + free(tsync_context->sync_offsets); + tsync_context->sync_ts = NULL; + tsync_context->sync_offsets = NULL; + tsync_context->sync_count = 0; + tsync_context->sync_size = 0; + pthread_mutex_destroy(&tsync->lock); + pthread_cond_destroy(&tsync->cond); + free(tsync->clock_str); +} + +int tracecmd_tsync_send(struct tracecmd_time_sync *tsync, + struct tsync_proto *proto) +{ + long long timestamp = 0; + long long offset = 0; + int ret; + + ret = proto->clock_sync_calc(tsync, &offset, ×tamp); + + return ret; +} + +/** + * tracecmd_tsync_with_host - Synchronize timestamps with host + * + * @tsync: Pointer to time sync context + * + * This API is supposed to be called in guest context. It waits for a time + * sync request from the host and replies with a time sample, until time sync + * stop command is received + * + */ +void tracecmd_tsync_with_host(struct tracecmd_time_sync *tsync) +{ + struct tsync_proto *proto; + unsigned int protocol; + unsigned int command; + int ret; + + proto = tsync_proto_find(tsync->sync_proto); + if (!proto || !proto->clock_sync_calc) + return; + + clock_context_init(tsync, true); + if (!tsync->context) + return; + + while (true) { + ret = tracecmd_msg_recv_time_sync(tsync->msg_handle, + &protocol, &command, + NULL, NULL); + + if (ret || + protocol != TRACECMD_TIME_SYNC_PROTO_NONE || + command != TRACECMD_TIME_SYNC_CMD_PROBE) + break; + ret = tracecmd_tsync_send(tsync, proto); + if (ret) + break; + } +} + +static int tsync_get_sample(struct tracecmd_time_sync *tsync, + struct tsync_proto *proto, int array_step) +{ + struct clock_sync_context *clock; + long long *sync_offsets = NULL; + long long *sync_ts = NULL; + long long timestamp = 0; + long long offset = 0; + int ret; + + ret = proto->clock_sync_calc(tsync, &offset, ×tamp); + if (ret) { + warning("Failed to synchronize timestamps with guest"); + return -1; + } + if (!offset || !timestamp) + return 0; + clock = tsync->context; + if (clock->sync_count >= clock->sync_size) { + sync_ts = realloc(clock->sync_ts, + (clock->sync_size + array_step) * sizeof(long long)); + sync_offsets = realloc(clock->sync_offsets, + (clock->sync_size + array_step) * sizeof(long long)); + if (!sync_ts || !sync_offsets) { + free(sync_ts); + free(sync_offsets); + return -1; + } + clock->sync_size += array_step; + clock->sync_ts = sync_ts; + clock->sync_offsets = sync_offsets; + } + + clock->sync_ts[clock->sync_count] = timestamp; + clock->sync_offsets[clock->sync_count] = offset; + clock->sync_count++; + + return 0; +} + +#define TIMER_SEC_NANO 1000000000LL +static inline void get_ts_loop_delay(struct timespec *timeout, int delay_ms) +{ + memset(timeout, 0, sizeof(struct timespec)); + clock_gettime(CLOCK_REALTIME, timeout); + + timeout->tv_nsec += ((unsigned long long)delay_ms * 1000000LL); + + if (timeout->tv_nsec >= TIMER_SEC_NANO) { + timeout->tv_sec += timeout->tv_nsec / TIMER_SEC_NANO; + timeout->tv_nsec %= TIMER_SEC_NANO; + } +} + +#define CLOCK_TS_ARRAY 5 +/** + * tracecmd_tsync_with_guest - Synchronize timestamps with guest + * + * @tsync: Pointer to time sync context + * + * This API is supposed to be called in host context, in a separate thread + * It loops infinite, until the timesync semaphore is released + * + */ +void tracecmd_tsync_with_guest(struct tracecmd_time_sync *tsync) +{ + int ts_array_size = CLOCK_TS_ARRAY; + struct tsync_proto *proto; + struct timespec timeout; + bool end = false; + int ret; + + proto = tsync_proto_find(tsync->sync_proto); + if (!proto || !proto->clock_sync_calc) + return; + + clock_context_init(tsync, false); + if (!tsync->context) + return; + + if (tsync->loop_interval > 0 && + tsync->loop_interval < (CLOCK_TS_ARRAY * 1000)) + ts_array_size = (CLOCK_TS_ARRAY * 1000) / tsync->loop_interval; + + while (true) { + pthread_mutex_lock(&tsync->lock); + ret = tracecmd_msg_send_time_sync(tsync->msg_handle, + TRACECMD_TIME_SYNC_PROTO_NONE, + TRACECMD_TIME_SYNC_CMD_PROBE, + 0, NULL); + ret = tsync_get_sample(tsync, proto, ts_array_size); + if (ret || end) + break; + if (tsync->loop_interval > 0) { + get_ts_loop_delay(&timeout, tsync->loop_interval); + ret = pthread_cond_timedwait(&tsync->cond, &tsync->lock, &timeout); + pthread_mutex_unlock(&tsync->lock); + if (ret && ret != ETIMEDOUT) + break; + else if (!ret) + end = true; + } else { + pthread_cond_wait(&tsync->cond, &tsync->lock); + end = true; + pthread_mutex_unlock(&tsync->lock); + } + }; + + tracecmd_msg_send_time_sync(tsync->msg_handle, + TRACECMD_TIME_SYNC_PROTO_NONE, + TRACECMD_TIME_SYNC_CMD_STOP, + 0, NULL); +} diff --git a/tracecmd/Makefile b/tracecmd/Makefile index 0976341c..17e67600 100644 --- a/tracecmd/Makefile +++ b/tracecmd/Makefile @@ -31,6 +31,7 @@ TRACE_CMD_OBJS += trace-show.o TRACE_CMD_OBJS += trace-list.o TRACE_CMD_OBJS += trace-usage.o TRACE_CMD_OBJS += trace-dump.o +TRACE_CMD_OBJS += trace-tsync.o ifeq ($(VSOCK_DEFINED), 1) TRACE_CMD_OBJS += trace-agent.o @@ -43,7 +44,7 @@ all_objs := $(sort $(ALL_OBJS)) all_deps := $(all_objs:$(bdir)/%.o=$(bdir)/.%.d) CONFIG_INCLUDES = -CONFIG_LIBS = -lrt +CONFIG_LIBS = -lrt -lpthread CONFIG_FLAGS = all: $(TARGETS) diff --git a/tracecmd/include/trace-local.h b/tracecmd/include/trace-local.h index 95d0026b..49c52b17 100644 --- a/tracecmd/include/trace-local.h +++ b/tracecmd/include/trace-local.h @@ -229,6 +229,10 @@ struct buffer_instance { unsigned int port; int *fds; bool use_fifos; + + pthread_t tsync_thread; + bool tsync_thread_running; + struct tracecmd_time_sync tsync; }; void init_top_instance(void); @@ -263,6 +267,13 @@ void tracecmd_disable_tracing(void); void tracecmd_enable_tracing(void); void tracecmd_stat_cpu(struct trace_seq *s, int cpu); +int tracecmd_host_tsync(struct buffer_instance *instance, + unsigned int tsync_port); +void tracecmd_host_tsync_complete(struct buffer_instance *instance); +unsigned int tracecmd_guest_tsync(char *tsync_protos, + unsigned int tsync_protos_size, char *clock, + unsigned int *tsync_port, pthread_t *thr_id); + int trace_make_vsock(unsigned int port); int trace_get_vsock_port(int sd, unsigned int *port); int trace_open_vsock(unsigned int cid, unsigned int port); diff --git a/tracecmd/trace-agent.c b/tracecmd/trace-agent.c index a8ef0852..b5816966 100644 --- a/tracecmd/trace-agent.c +++ b/tracecmd/trace-agent.c @@ -19,6 +19,7 @@ #include #include #include +#include #include "trace-local.h" #include "trace-msg.h" @@ -125,11 +126,30 @@ cleanup: return ret; } +static char *get_clock(int argc, char **argv) +{ + int i; + + if (!argc || !argv) + return NULL; + + for (i = 0; i < argc - 1; i++) { + if (!strcmp("-C", argv[i])) + return argv[i+1]; + } + return NULL; +} + static void agent_handle(int sd, int nr_cpus, int page_size) { struct tracecmd_msg_handle *msg_handle; + unsigned int tsync_protos_size = 0; + unsigned int tsync_proto = 0; unsigned long long trace_id; + unsigned int tsync_port = 0; + char *tsync_protos = NULL; unsigned int *ports; + pthread_t sync_thr; char **argv = NULL; int argc = 0; bool use_fifos; @@ -146,7 +166,8 @@ static void agent_handle(int sd, int nr_cpus, int page_size) die("Failed to allocate message handle"); ret = tracecmd_msg_recv_trace_req(msg_handle, &argc, &argv, - &use_fifos, &trace_id); + &use_fifos, &trace_id, + &tsync_protos, &tsync_protos_size); if (ret < 0) die("Failed to receive trace request"); @@ -155,16 +176,28 @@ static void agent_handle(int sd, int nr_cpus, int page_size) if (!use_fifos) make_vsocks(nr_cpus, fds, ports); - + if (tsync_protos) { + tsync_proto = tracecmd_guest_tsync(tsync_protos, + tsync_protos_size, + get_clock(argc, argv), + &tsync_port, &sync_thr); + if (!tsync_proto) + warning("Failed to negotiate timestamps synchronization with the host"); + } trace_id = tracecmd_generate_traceid(); ret = tracecmd_msg_send_trace_resp(msg_handle, nr_cpus, page_size, - ports, use_fifos, trace_id); + ports, use_fifos, trace_id, + tsync_proto, tsync_port); if (ret < 0) die("Failed to send trace response"); trace_record_agent(msg_handle, nr_cpus, fds, argc, argv, use_fifos, trace_id); + if (tsync_proto) + pthread_join(sync_thr, NULL); + + free(tsync_protos); free(argv[0]); free(argv); free(ports); diff --git a/tracecmd/trace-record.c b/tracecmd/trace-record.c index 30ba5bb2..a60a5531 100644 --- a/tracecmd/trace-record.c +++ b/tracecmd/trace-record.c @@ -672,6 +672,11 @@ static void tell_guests_to_stop(void) tracecmd_msg_send_close_msg(instance->msg_handle); } + for_all_instances(instance) { + if (is_guest(instance)) + tracecmd_host_tsync_complete(instance); + } + /* Wait for guests to acknowledge */ for_all_instances(instance) { if (is_guest(instance)) { @@ -3678,6 +3683,10 @@ static void connect_to_agent(struct buffer_instance *instance) { struct tracecmd_msg_handle *msg_handle; int sd, ret, nr_fifos, nr_cpus, page_size; + unsigned int tsync_protos_reply = 0; + unsigned int tsync_port = 0; + char *protos = NULL; + int protos_count = 0; unsigned int *ports; int i, *fds = NULL; bool use_fifos = false; @@ -3698,17 +3707,32 @@ static void connect_to_agent(struct buffer_instance *instance) if (!msg_handle) die("Failed to allocate message handle"); + if (instance->tsync.loop_interval >= 0) + tracecmd_tsync_proto_getall(&protos, &protos_count); + ret = tracecmd_msg_send_trace_req(msg_handle, instance->argc, instance->argv, use_fifos, - top_instance.trace_id); + top_instance.trace_id, + protos, protos_count); if (ret < 0) die("Failed to send trace request"); + free(protos); + ret = tracecmd_msg_recv_trace_resp(msg_handle, &nr_cpus, &page_size, &ports, &use_fifos, - &instance->trace_id); + &instance->trace_id, + &tsync_protos_reply, &tsync_port); if (ret < 0) - die("Failed to receive trace response"); + die("Failed to receive trace response %d", ret); + + if (protos_count && tsync_protos_reply) { + if (tsync_proto_is_supported(tsync_protos_reply)) { + instance->tsync.sync_proto = tsync_protos_reply; + tracecmd_host_tsync(instance, tsync_port); + } else + warning("Failed to negotiate timestamps synchronization with the guest"); + } if (use_fifos) { if (nr_cpus != nr_fifos) { @@ -3756,7 +3780,8 @@ 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; @@ -5281,6 +5306,7 @@ void init_top_instance(void) } enum { + OPT_tsyncinterval = 242, OPT_user = 243, OPT_procmap = 244, OPT_quiet = 245, @@ -5583,6 +5609,7 @@ static void parse_record_options(int argc, {"proc-map", no_argument, NULL, OPT_procmap}, {"user", required_argument, NULL, OPT_user}, {"module", required_argument, NULL, OPT_module}, + {"tsync-interval", required_argument, NULL, OPT_tsyncinterval}, {NULL, 0, NULL, 0} }; @@ -5925,6 +5952,10 @@ static void parse_record_options(int argc, ctx->instance->filter_mod = optarg; ctx->filtered = 0; break; + case OPT_tsyncinterval: + top_instance.tsync.loop_interval = atoi(optarg); + guest_sync_set = true; + break; case OPT_quiet: case 'q': quiet = true; @@ -5955,6 +5986,7 @@ static void parse_record_options(int argc, add_argv(instance, "-C", true); } } + instance->tsync.loop_interval = top_instance.tsync.loop_interval; } } diff --git a/tracecmd/trace-tsync.c b/tracecmd/trace-tsync.c new file mode 100644 index 00000000..bf65e441 --- /dev/null +++ b/tracecmd/trace-tsync.c @@ -0,0 +1,272 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (C) 2019, VMware, Tzvetomir Stoyanov + * + */ +#include +#include +#include +#include +#include +#include +#include + +#include "tracefs.h" +#include "trace-local.h" +#include "trace-msg.h" + +static int get_first_cpu(cpu_set_t **pin_mask, size_t *m_size) +{ + int cpus = tracecmd_count_cpus(); + cpu_set_t *cpu_mask; + int mask_size; + int i; + + cpu_mask = CPU_ALLOC(cpus); + *pin_mask = CPU_ALLOC(cpus); + if (!cpu_mask || !*pin_mask || 1) + goto error; + + mask_size = CPU_ALLOC_SIZE(cpus); + CPU_ZERO_S(mask_size, cpu_mask); + CPU_ZERO_S(mask_size, *pin_mask); + + if (sched_getaffinity(0, mask_size, cpu_mask) == -1) + goto error; + + for (i = 0; i < cpus; i++) { + if (CPU_ISSET_S(i, mask_size, cpu_mask)) { + CPU_SET_S(i, mask_size, *pin_mask); + break; + } + } + + if (CPU_COUNT_S(mask_size, *pin_mask) < 1) + goto error; + + CPU_FREE(cpu_mask); + *m_size = mask_size; + return 0; + +error: + if (cpu_mask) + CPU_FREE(cpu_mask); + if (*pin_mask) + CPU_FREE(*pin_mask); + *pin_mask = NULL; + *m_size = 0; + return -1; +} + +static void *tsync_host_thread(void *data) +{ + struct tracecmd_time_sync *tsync = NULL; + + tsync = (struct tracecmd_time_sync *)data; + + tracecmd_tsync_with_guest(tsync); + + tracecmd_msg_handle_close(tsync->msg_handle); + tsync->msg_handle = NULL; + + pthread_exit(0); +} + +int tracecmd_host_tsync(struct buffer_instance *instance, + unsigned int tsync_port) +{ + struct tracecmd_msg_handle *msg_handle = NULL; + cpu_set_t *pin_mask = NULL; + pthread_attr_t attrib; + size_t mask_size = 0; + int ret; + int fd; + + if (!instance->tsync.sync_proto) + return -1; + + fd = trace_open_vsock(instance->cid, tsync_port); + if (fd < 0) { + ret = -1; + goto out; + } + msg_handle = tracecmd_msg_handle_alloc(fd, 0); + if (!msg_handle) { + ret = -1; + goto out; + } + + instance->tsync.msg_handle = msg_handle; + if (top_instance.clock) + instance->tsync.clock_str = strdup(top_instance.clock); + pthread_mutex_init(&instance->tsync.lock, NULL); + pthread_cond_init(&instance->tsync.cond, NULL); + + pthread_attr_init(&attrib); + pthread_attr_setdetachstate(&attrib, PTHREAD_CREATE_JOINABLE); + if (!get_first_cpu(&pin_mask, &mask_size)) + pthread_attr_setaffinity_np(&attrib, mask_size, pin_mask); + + ret = pthread_create(&instance->tsync_thread, &attrib, + tsync_host_thread, &instance->tsync); + if (!ret) + instance->tsync_thread_running = true; + if (pin_mask) + CPU_FREE(pin_mask); + pthread_attr_destroy(&attrib); + +out: + if (ret) { + if (msg_handle) + tracecmd_msg_handle_close(msg_handle); + } + + return ret; +} + +static void write_guest_time_shift(struct buffer_instance *instance) +{ + struct tracecmd_output *handle; + struct iovec vector[4]; + long long *offsets; + long long *ts; + char *file; + int count; + int ret; + int fd; + + ret = tracecmd_tsync_get_offsets(&instance->tsync, &count, &ts, &offsets); + if (ret < 0 || !count || !ts || !offsets) + return; + + file = trace_get_guest_file(DEFAUT_INPUT_FILE, + tracefs_instance_get_name(instance->tracefs)); + fd = open(file, O_RDWR); + if (fd < 0) + die("error opening %s", file); + free(file); + handle = tracecmd_get_output_handle_fd(fd); + vector[0].iov_len = 8; + vector[0].iov_base = &top_instance.trace_id; + vector[1].iov_len = 4; + vector[1].iov_base = &count; + vector[2].iov_len = 8 * count; + vector[2].iov_base = ts; + vector[3].iov_len = 8 * count; + vector[3].iov_base = offsets; + tracecmd_add_option_v(handle, TRACECMD_OPTION_TIME_SHIFT, vector, 4); + tracecmd_append_options(handle); + tracecmd_output_close(handle); +#ifdef TSYNC_DEBUG + if (count > 1) + printf("Got %d timestamp synch samples for guest %s in %lld ns trace\n\r", + count, tracefs_instance_get_name(instance->tracefs), + ts[count - 1] - ts[0]); +#endif +} + +void tracecmd_host_tsync_complete(struct buffer_instance *instance) +{ + if (!instance->tsync_thread_running) + return; + + /* Signal the time synchronization thread to complete and wait for it */ + pthread_mutex_lock(&instance->tsync.lock); + pthread_cond_signal(&instance->tsync.cond); + pthread_mutex_unlock(&instance->tsync.lock); + pthread_join(instance->tsync_thread, NULL); + write_guest_time_shift(instance); + tracecmd_tsync_free(&instance->tsync); +} + +static void *tsync_agent_thread(void *data) +{ + struct tracecmd_time_sync *tsync = NULL; + int sd; + + tsync = (struct tracecmd_time_sync *)data; + + while (true) { + sd = accept(tsync->msg_handle->fd, NULL, NULL); + if (sd < 0) { + if (errno == EINTR) + continue; + goto out; + } + break; + } + close(tsync->msg_handle->fd); + tsync->msg_handle->fd = sd; + + tracecmd_tsync_with_host(tsync); + +out: + tracecmd_msg_handle_close(tsync->msg_handle); + tracecmd_tsync_free(tsync); + free(tsync); + close(sd); + + pthread_exit(0); +} + +unsigned int tracecmd_guest_tsync(char *tsync_protos, + unsigned int tsync_protos_size, char *clock, + unsigned int *tsync_port, pthread_t *thr_id) +{ + struct tracecmd_time_sync *tsync = NULL; + cpu_set_t *pin_mask = NULL; + pthread_attr_t attrib; + size_t mask_size = 0; + unsigned int proto; + int ret; + int fd; + + fd = -1; + proto = tracecmd_tsync_proto_select(tsync_protos, tsync_protos_size); + if (!proto) + return 0; +#ifdef VSOCK + fd = trace_make_vsock(VMADDR_PORT_ANY); + if (fd < 0) + goto error; + + ret = trace_get_vsock_port(fd, tsync_port); + if (ret < 0) + goto error; +#else + return 0; +#endif + + tsync = calloc(1, sizeof(struct tracecmd_time_sync)); + tsync->msg_handle = tracecmd_msg_handle_alloc(fd, 0); + if (clock) + tsync->clock_str = strdup(clock); + + pthread_attr_init(&attrib); + tsync->sync_proto = proto; + pthread_attr_setdetachstate(&attrib, PTHREAD_CREATE_JOINABLE); + if (!get_first_cpu(&pin_mask, &mask_size)) + pthread_attr_setaffinity_np(&attrib, mask_size, pin_mask); + + ret = pthread_create(thr_id, &attrib, tsync_agent_thread, tsync); + + if (pin_mask) + CPU_FREE(pin_mask); + pthread_attr_destroy(&attrib); + + if (ret) + goto error; + + return proto; + +error: + if (tsync) { + if (tsync->msg_handle) + tracecmd_msg_handle_close(tsync->msg_handle); + free(tsync->clock_str); + free(tsync); + } + if (fd > 0) + close(fd); + return 0; +} diff --git a/tracecmd/trace-usage.c b/tracecmd/trace-usage.c index 502a4102..d43ca490 100644 --- a/tracecmd/trace-usage.c +++ b/tracecmd/trace-usage.c @@ -60,6 +60,10 @@ static struct usage_help usage_help[] = { " --no-filter include trace-cmd threads in the trace\n" " --proc-map save the traced processes address map into the trace.dat file\n" " --user execute the specified [command ...] as given user\n" + " --tsync-interval set the loop interval, in ms, for timestamps synchronization with guests:" + " If a negative number is specified, timestamps synchronization is disabled" + " If 0 is specified, no loop is performed - timestamps offset is calculated only twice," + " at the beginnig and at the end of the trace\n" }, { "start", From patchwork Thu Feb 27 14:20:00 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: "Tzvetomir Stoyanov (VMware)" X-Patchwork-Id: 11408707 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 EAC971805 for ; Thu, 27 Feb 2020 14:20:49 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.kernel.org (Postfix) with ESMTP id ADFA424690 for ; Thu, 27 Feb 2020 14:20:49 +0000 (UTC) Authentication-Results: mail.kernel.org; dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b="orpEbxL3" Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S2389244AbgB0OUt (ORCPT ); Thu, 27 Feb 2020 09:20:49 -0500 Received: from mail-lj1-f196.google.com ([209.85.208.196]:39158 "EHLO mail-lj1-f196.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S2389892AbgB0OU1 (ORCPT ); Thu, 27 Feb 2020 09:20:27 -0500 Received: by mail-lj1-f196.google.com with SMTP id o15so3615520ljg.6 for ; Thu, 27 Feb 2020 06:20:25 -0800 (PST) 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=eDflHXWoiqn3PTMXXSZoGxFVt2ykcr+jjiFjUsJPrxk=; b=orpEbxL3jhuELDEsJuyAiPa6ZIK9GbWNQbY5jVAX/jLQznXYIh5o1Ycazztw5VrA+n vJ01FoO3C/ZbnUT5v4deoaWg9m5lsBal/NIuYEV2AnYGV6niRtoYo07aWjRdxNIt9Fer gcSsyWbEFs8cYo5ZP0v4ORQYmPzXPYKm6fHD4F2z9v9Yr/yZx4IwKO0Fk22AQhDUHc57 Waf+e5x2mPUybSZ9cFRuECA4+Xas9FmviTNXNVmLWlNTWb4vgQlpqa91mgKLIp8R64xY Xnieqlu14C2IvXIuvNHQ5vnHDGldkF/f6Dm4BzAB+YaHmDooFOU/UR3WHbzjX+vPXWIb dEcA== 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=eDflHXWoiqn3PTMXXSZoGxFVt2ykcr+jjiFjUsJPrxk=; b=Dn/pCUnouDQBoIkuIcZy4ffuL86r0hGMnC0nTvqTw++l3AfMQOT1zxD0A6I+rRPnSG JgrCnNCdWynfSC8siDm65QMT89f5R+kYHtWgXuzm7TSrQ5DTWpKddCxfbxYF4saoPnuZ RtRW2mfeJOPgfGC9vhp/biA9gQD7fPBtqIZodDr+rrHuhOZwgAEB+ORgr6umazf78MWy SpRXwHXXa5CDHZlPSo+sHQ+t6cTOTbbgC+7p8Wy4zMTEgdcVyPbHq0gMHpAsbpHg2VYZ b/wglGNXoglFHHxwJ55A+jAtvcNwS2PTQ+LjKWWQV6K3gSS9VyDu0nqjfenUjTGsirl5 1Wmg== X-Gm-Message-State: ANhLgQ26uPFpLkdDyrxofYvMIt94tjTI2+JrxWwDhYVmN9BVDZwnm0c3 wz7NI3noXuW40oVr2tIE8+H5n4lBRm4= X-Google-Smtp-Source: ADFU+vtXivD+wy/B9sZWP2kWtE5o3fbYoX0PETRODAj21IJj7MpR9vN1QhY+fFogKzggBlevbF+UxQ== X-Received: by 2002:a2e:9705:: with SMTP id r5mr3134557lji.114.1582813224098; Thu, 27 Feb 2020 06:20:24 -0800 (PST) Received: from oberon.zico.biz ([83.222.187.186]) by smtp.gmail.com with ESMTPSA id l3sm3306437lja.78.2020.02.27.06.20.22 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Thu, 27 Feb 2020 06:20:22 -0800 (PST) From: "Tzvetomir Stoyanov (VMware)" To: rostedt@goodmis.org Cc: linux-trace-devel@vger.kernel.org Subject: [PATCH v20 14/15] trace-cmd: [POC] PTP-like algorithm for host - guest timestamp synchronization Date: Thu, 27 Feb 2020 16:20:00 +0200 Message-Id: <20200227142001.61577-15-tz.stoyanov@gmail.com> X-Mailer: git-send-email 2.24.1 In-Reply-To: <20200227142001.61577-1-tz.stoyanov@gmail.com> References: <20200227142001.61577-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 PTP protocol is designed for synchronizing clocks of machines in a local network. The same approach can be used for host - guest timestamp synchronization. This implementation uses ftrace raw markers to track trace timestamps of PTP events. The patch is a POC, two different algorithms for PTP calculations are proposed: - Choosing the sample with the fastest response time for calculating the clocks offset. - Calculating the clocks offset using the average of all PTP samples. The implementation can be tuned using those parameters: - #define FASTEST_RESPONSE - is defined, the sample with the fastest response time is used for calculating the clocks offset. Otherwise the histogram of all samples is used. - #define PTP_SYNC_LOOP 340 - defines the number of samples, used for one calculation. - --tsync-interval - a trace-cmd argument, choose the intervals between offset calculations, performed continuously during the trace. - #define TSYNC_DEBUG - if defined, a debug information is collected and stored in files, in the guest machine: s-cid*.txt - For each offset calculation: host and guest clocks and calculated offset. res-cid*.txt - For each tracing session: all calculated clock offsets. Signed-off-by: Tzvetomir Stoyanov (VMware) --- include/trace-cmd/trace-cmd.h | 1 + lib/trace-cmd/Makefile | 1 + lib/trace-cmd/trace-timesync-ptp.c | 651 +++++++++++++++++++++++++++++ lib/trace-cmd/trace-timesync.c | 8 + tracecmd/trace-agent.c | 2 + tracecmd/trace-record.c | 23 +- 6 files changed, 678 insertions(+), 8 deletions(-) create mode 100644 lib/trace-cmd/trace-timesync-ptp.c diff --git a/include/trace-cmd/trace-cmd.h b/include/trace-cmd/trace-cmd.h index 42b47e2f..b5207248 100644 --- a/include/trace-cmd/trace-cmd.h +++ b/include/trace-cmd/trace-cmd.h @@ -414,6 +414,7 @@ int tracecmd_msg_recv_time_sync(struct tracecmd_msg_handle *msg_handle, enum{ TRACECMD_TIME_SYNC_PROTO_NONE = 0, + TRACECMD_TIME_SYNC_PROTO_PTP = 1, }; enum{ TRACECMD_TIME_SYNC_CMD_PROBE = 1, diff --git a/lib/trace-cmd/Makefile b/lib/trace-cmd/Makefile index ab7440ac..79672529 100644 --- a/lib/trace-cmd/Makefile +++ b/lib/trace-cmd/Makefile @@ -17,6 +17,7 @@ OBJS += trace-filter-hash.o OBJS += trace-msg.o OBJS += trace-plugin.o OBJS += trace-timesync.o +OBJS += trace-timesync-ptp.o # Additional util objects OBJS += trace-blk-hack.o diff --git a/lib/trace-cmd/trace-timesync-ptp.c b/lib/trace-cmd/trace-timesync-ptp.c new file mode 100644 index 00000000..d1e2fae8 --- /dev/null +++ b/lib/trace-cmd/trace-timesync-ptp.c @@ -0,0 +1,651 @@ +// SPDX-License-Identifier: LGPL-2.1 +/* + * Copyright (C) 2019, VMware, Tzvetomir Stoyanov tz.stoyanov@gmail.com> + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "trace-cmd.h" +#include "tracefs.h" +#include "trace-tsync-local.h" +#include "trace-msg.h" +#include "trace-cmd-local.h" + +typedef __be32 be32; +typedef __u64 u64; +typedef __s64 s64; + +#define PTP_SYNC_LOOP 340 + +#define PTP_SYNC_PKT_START 1 +#define PTP_SYNC_PKT_PROBE 2 +#define PTP_SYNC_PKT_PROBES 3 +#define PTP_SYNC_PKT_OFFSET 4 +#define PTP_SYNC_PKT_END 5 + +#define TSYNC_DEBUG + +struct ptp_clock_sync { + struct tep_handle *tep; + int raw_id; + int marker_fd; + int series_id; + int debug_fd; + +}; + +struct ptp_clock_start_msg { + be32 series_id; +} __attribute__((packed)); + +struct ptp_clock_sample { + s64 ts; + be32 id; +} __attribute__((packed)); + +struct ptp_clock_result_msg { + be32 series_id; + be32 count; + struct ptp_clock_sample samples[2*PTP_SYNC_LOOP]; +} __attribute__((packed)); + +struct ptp_clock_offset_msg { + s64 ts; + s64 offset; +}; + +struct ptp_markers_context { + struct clock_sync_context *clock; + struct ptp_clock_sync *ptp; + int size; + struct ptp_clock_result_msg msg; +}; + +struct ptp_marker_buf { + int local_cid; + int remote_cid; + int count; + int packet_id; +} __attribute__((packed)); + +struct ptp_marker { + int series_id; + struct ptp_marker_buf data; +} __attribute__((packed)); + +static int ptp_clock_sync_init(struct tracecmd_time_sync *tsync) +{ + const char *systems[] = {"ftrace", NULL}; + struct clock_sync_context *clock_context; + struct ptp_clock_sync *ptp; + struct tep_event *raw; + char *path; + + if (!tsync || !tsync->context) + return -1; + clock_context = (struct clock_sync_context *)tsync->context; + if (clock_context->proto_data) + return 0; + + ptp = calloc(1, sizeof(struct ptp_clock_sync)); + if (!ptp) + return -1; + + ptp->marker_fd = -1; + ptp->debug_fd = -1; + + path = tracefs_instance_get_dir(clock_context->instance); + if (!path) + goto error; + ptp->tep = tracefs_local_events_system(path, systems); + tracefs_put_tracing_file(path); + if (!ptp->tep) + goto error; + raw = tep_find_event_by_name(ptp->tep, "ftrace", "raw_data"); + if (!raw) + goto error; + + ptp->raw_id = raw->id; + tep_set_file_bigendian(ptp->tep, tracecmd_host_bigendian()); + tep_set_local_bigendian(ptp->tep, tracecmd_host_bigendian()); + + path = tracefs_instance_get_file(clock_context->instance, "trace_marker_raw"); + if (!path) + goto error; + ptp->marker_fd = open(path, O_WRONLY); + tracefs_put_tracing_file(path); + + clock_context->proto_data = ptp; + +#ifdef TSYNC_DEBUG + if (clock_context->is_server) { + char buff[256]; + int res_fd; + + sprintf(buff, "res-cid%d.txt", clock_context->remote_cid); + + res_fd = open(buff, O_CREAT|O_WRONLY|O_TRUNC, 0644); + if (res_fd > 0) + close(res_fd); + } +#endif + + return 0; + +error: + if (ptp) { + tep_free(ptp->tep); + if (ptp->marker_fd >= 0) + close(ptp->marker_fd); + } + free(ptp); + return -1; +} + +static int ptp_clock_sync_free(struct tracecmd_time_sync *tsync) +{ + struct clock_sync_context *clock_context; + struct ptp_clock_sync *ptp; + + if (!tsync || !tsync->context) + return -1; + clock_context = (struct clock_sync_context *)tsync->context; + + if (clock_context && clock_context->proto_data) { + ptp = (struct ptp_clock_sync *)clock_context->proto_data; + tep_free(ptp->tep); + if (ptp->marker_fd >= 0) + close(ptp->marker_fd); + if (ptp->debug_fd >= 0) + close(ptp->debug_fd); + free(clock_context->proto_data); + clock_context->proto_data = NULL; + } + return 0; +} + +static int ptp_marker_find(struct tep_event *event, struct tep_record *record, + int cpu, void *context) +{ + struct ptp_markers_context *ctx; + struct tep_format_field *field; + struct tep_format_field *id; + struct ptp_marker *marker; + int index = -1; + + ctx = (struct ptp_markers_context *)context; + + /* Make sure this is our event */ + if (event->id != ctx->ptp->raw_id) + return 0; + id = tep_find_field(event, "id"); + field = tep_find_field(event, "buf"); + if (field && id && + record->size >= (id->offset + sizeof(struct ptp_marker))) { + marker = (struct ptp_marker *)(record->data + id->offset); + if (marker->data.local_cid == ctx->clock->local_cid && + marker->data.remote_cid == ctx->clock->remote_cid && + marker->series_id == ctx->ptp->series_id && + marker->data.count) { + if (marker->data.packet_id == 'r' && + marker->data.count <= ctx->size) { + index = marker->data.count - 1; + } else if (marker->data.packet_id == 's' && + marker->data.count*2 <= ctx->size){ + index = ctx->size / 2 + marker->data.count - 1; + } + } + if (index >= 0) { + ctx->msg.samples[index].id = marker->data.count; + ctx->msg.samples[index].ts = record->ts; + ctx->msg.count++; + } + } + + return 0; +} + +//#define FASTEST_RESPONSE + +#ifdef FASTEST_RESPONSE +static int ptp_calc_offset(struct clock_sync_context *clock, + struct ptp_clock_result_msg *server, + struct ptp_clock_result_msg *client, + long long *offset_ret, long long *ts_ret, + int *bad_probes) +{ + struct ptp_clock_sample *sample_send; + long long delta_min = 0; + long long offset = 0; + long long delta = 0; + long long ts = 0; + int i; + + *bad_probes = 0; + sample_send = server->samples + (server->count / 2); + for (i = 0; i * 2 < server->count && i < client->count; i++) { + if (!server->samples[i].ts || + !sample_send[i].ts || + !client->samples[i].ts || + server->samples[i].id != sample_send[i].id || + server->samples[i].id != client->samples[i].id) { + (*bad_probes)++; + continue; + } + + ts = (sample_send[i].ts + server->samples[i].ts) / 2; + offset = client->samples[i].ts - ts; + + delta = server->samples[i].ts - sample_send[i].ts; + if (!delta_min || delta_min > delta) { + delta_min = delta; + *offset_ret = offset; + *ts_ret = ts; + } +#ifdef TSYNC_DEBUG + { + struct ptp_clock_sync *ptp; + + ptp = (struct ptp_clock_sync *)clock->proto_data; + if (ptp && ptp->debug_fd > 0) { + char buff[256]; + + sprintf(buff, "%lld %lld %lld\n", + ts, client->samples[i].ts, offset); + write(ptp->debug_fd, buff, strlen(buff)); + } + } +#endif + } + + return 0; +} + +#else /* histogram */ + +static int ptp_calc_offset(struct clock_sync_context *clock, + struct ptp_clock_result_msg *server, + struct ptp_clock_result_msg *client, + long long *offset_ret, long long *ts_ret, + int *bad_probes) +{ + struct ptp_clock_sample *sample_send; + long long timestamps[PTP_SYNC_LOOP]; + long long offsets[PTP_SYNC_LOOP]; + int hist[PTP_SYNC_LOOP]; + long long offset_max = 0; + long long offset_min = 0; + int ind, max = 0; + long long bin; + int i, k = 0; + + *bad_probes = 0; + memset(hist, 0, sizeof(int) * PTP_SYNC_LOOP); + sample_send = server->samples + (server->count / 2); + for (i = 0; i * 2 < server->count && i < client->count; i++) { + if (!server->samples[i].ts || + !sample_send[i].ts || + !client->samples[i].ts || + server->samples[i].id != sample_send[i].id || + server->samples[i].id != client->samples[i].id) { + (*bad_probes)++; + continue; + } + + timestamps[k] = (sample_send[i].ts + server->samples[i].ts) / 2; + offsets[k] = client->samples[i].ts - timestamps[k]; + if (!offset_max || offset_max < llabs(offsets[k])) + offset_max = llabs(offsets[k]); + if (!offset_min || offset_min > llabs(offsets[k])) + offset_min = llabs(offsets[k]); +#ifdef TSYNC_DEBUG + { + struct ptp_clock_sync *ptp; + + ptp = (struct ptp_clock_sync *)clock->proto_data; + + if (ptp && ptp->debug_fd > 0) { + char buff[256]; + + sprintf(buff, "%lld %lld %lld\n", + timestamps[k], + client->samples[i].ts, offsets[k]); + write(ptp->debug_fd, buff, strlen(buff)); + } + } +#endif + k++; + } + + bin = (offset_max - offset_min) / PTP_SYNC_LOOP; + for (i = 0; i < k; i++) { + ind = (llabs(offsets[i]) - offset_min) / bin; + if (ind < PTP_SYNC_LOOP) { + hist[ind]++; + if (max < hist[ind]) { + max = hist[ind]; + *offset_ret = offsets[i]; + *ts_ret = timestamps[i]; + } + } + } + + return 0; +} +#endif + +static void ntoh_ptp_results(struct ptp_clock_result_msg *msg) +{ + int i; + + msg->count = ntohl(msg->count); + for (i = 0; i < msg->count; i++) { + msg->samples[i].id = ntohl(msg->samples[i].id); + msg->samples[i].ts = ntohll(msg->samples[i].ts); + } + msg->series_id = ntohl(msg->series_id); +} + + +static void hton_ptp_results(struct ptp_clock_result_msg *msg) +{ + int i; + + for (i = 0; i < msg->count; i++) { + msg->samples[i].id = htonl(msg->samples[i].id); + msg->samples[i].ts = htonll(msg->samples[i].ts); + } + msg->series_id = htonl(msg->series_id); + msg->count = htonl(msg->count); +} + +static int ptp_clock_client(struct tracecmd_time_sync *tsync, + long long *offset, long long *timestamp) +{ + struct clock_sync_context *clock_context; + struct ptp_clock_offset_msg res_offset; + unsigned int sync_proto, sync_msg; + struct ptp_clock_start_msg start; + struct ptp_markers_context ctx; + struct ptp_clock_sync *ptp; + struct ptp_marker marker; + unsigned int size; + char *msg; + int count; + int ret; + + if (!tsync || !tsync->context || !tsync->msg_handle) + return -1; + + clock_context = (struct clock_sync_context *)tsync->context; + if (clock_context->proto_data == NULL) + return -1; + + ptp = (struct ptp_clock_sync *)clock_context->proto_data; + size = sizeof(start); + msg = (char *)&start; + ret = tracecmd_msg_recv_time_sync(tsync->msg_handle, + &sync_proto, &sync_msg, + &size, &msg); + if (ret || sync_proto != TRACECMD_TIME_SYNC_PROTO_PTP || + sync_msg != PTP_SYNC_PKT_START) + return -1; + ret = tracecmd_msg_send_time_sync(tsync->msg_handle, + TRACECMD_TIME_SYNC_PROTO_PTP, + PTP_SYNC_PKT_START, sizeof(start), + (char *)&start); + marker.data.local_cid = clock_context->local_cid; + marker.data.remote_cid = clock_context->remote_cid; + marker.series_id = ntohl(start.series_id); + marker.data.packet_id = 'r'; + ptp->series_id = marker.series_id; + msg = (char *)&count; + size = sizeof(count); + while (true) { + count = 0; + ret = tracecmd_msg_recv_time_sync(tsync->msg_handle, + &sync_proto, &sync_msg, + &size, &msg); + if (ret || sync_proto != TRACECMD_TIME_SYNC_PROTO_PTP || + sync_msg != PTP_SYNC_PKT_PROBE || !ntohl(count)) + break; + + marker.data.count = ntohl(count); + write(ptp->marker_fd, &marker, sizeof(marker)); + ret = tracecmd_msg_send_time_sync(tsync->msg_handle, + TRACECMD_TIME_SYNC_PROTO_PTP, + PTP_SYNC_PKT_PROBE, + sizeof(count), (char *)&count); + if (ret) + break; + } + + if (sync_proto != TRACECMD_TIME_SYNC_PROTO_PTP || + sync_msg != PTP_SYNC_PKT_END) + return -1; + + ctx.size = PTP_SYNC_LOOP; + ctx.ptp = ptp; + ctx.clock = clock_context; + ctx.msg.count = 0; + ctx.msg.series_id = ptp->series_id; + tracefs_iterate_raw_events(ptp->tep, clock_context->instance, + ptp_marker_find, &ctx); + hton_ptp_results(&ctx.msg); + ret = tracecmd_msg_send_time_sync(tsync->msg_handle, + TRACECMD_TIME_SYNC_PROTO_PTP, + PTP_SYNC_PKT_PROBES, + sizeof(ctx.msg), (char *)&ctx.msg); + + msg = (char *)&res_offset; + size = sizeof(res_offset); + ret = tracecmd_msg_recv_time_sync(tsync->msg_handle, + &sync_proto, &sync_msg, + &size, (char **)&msg); + if (ret || sync_proto != TRACECMD_TIME_SYNC_PROTO_PTP || + sync_msg != PTP_SYNC_PKT_OFFSET) + return -1; + + *offset = ntohll(res_offset.offset); + *timestamp = ntohll(res_offset.ts); + + return 0; +} + + +static int ptp_clock_server(struct tracecmd_time_sync *tsync, + long long *offset, long long *timestamp) +{ + struct ptp_clock_result_msg *results = NULL; + struct clock_sync_context *clock_context; + struct ptp_clock_offset_msg res_offset; + unsigned int sync_proto, sync_msg; + struct ptp_clock_start_msg start; + struct ptp_markers_context ctx; + int sync_loop = PTP_SYNC_LOOP; + struct ptp_clock_sync *ptp; + struct ptp_marker marker; + unsigned int size; + int bad_probes; + int count = 1; + int msg_count; + int msg_ret; + char *msg; + int ret; + + if (!tsync || !tsync->context || !tsync->msg_handle) + return -1; + + clock_context = (struct clock_sync_context *)tsync->context; + if (clock_context->proto_data == NULL) + return -1; + + ptp = (struct ptp_clock_sync *)clock_context->proto_data; + start.series_id = htonl(ptp->series_id + 1); + ret = tracecmd_msg_send_time_sync(tsync->msg_handle, + TRACECMD_TIME_SYNC_PROTO_PTP, + PTP_SYNC_PKT_START, sizeof(start), + (char *)&start); + if (!ret) + ret = tracecmd_msg_recv_time_sync(tsync->msg_handle, + &sync_proto, &sync_msg, + NULL, NULL); + if (ret || sync_proto != TRACECMD_TIME_SYNC_PROTO_PTP || + sync_msg != PTP_SYNC_PKT_START) + return -1; + + tracefs_instance_file_write(clock_context->instance, "trace", "\0"); + + ptp->series_id++; + marker.data.local_cid = clock_context->local_cid; + marker.data.remote_cid = clock_context->remote_cid; + marker.series_id = ptp->series_id; + msg = (char *)&msg_ret; + size = sizeof(msg_ret); + do { + marker.data.count = count++; + marker.data.packet_id = 's'; + msg_count = htonl(marker.data.count); + write(ptp->marker_fd, &marker, sizeof(marker)); + ret = tracecmd_msg_send_time_sync(tsync->msg_handle, + TRACECMD_TIME_SYNC_PROTO_PTP, + PTP_SYNC_PKT_PROBE, + sizeof(msg_count), + (char *)&msg_count); + if (!ret) + ret = tracecmd_msg_recv_time_sync(tsync->msg_handle, + &sync_proto, &sync_msg, + &size, &msg); + + marker.data.packet_id = 'r'; + write(ptp->marker_fd, &marker, sizeof(marker)); + if (ret || sync_proto != TRACECMD_TIME_SYNC_PROTO_PTP || + sync_msg != PTP_SYNC_PKT_PROBE || + ntohl(msg_ret) != marker.data.count) + break; + } while (--sync_loop); + + if (sync_loop) + return -1; + + ret = tracecmd_msg_send_time_sync(tsync->msg_handle, + TRACECMD_TIME_SYNC_PROTO_PTP, + PTP_SYNC_PKT_END, 0, NULL); + + size = 0; + ret = tracecmd_msg_recv_time_sync(tsync->msg_handle, + &sync_proto, &sync_msg, + &size, (char **)&results); + if (ret || sync_proto != TRACECMD_TIME_SYNC_PROTO_PTP || + sync_msg != PTP_SYNC_PKT_PROBES || size == 0 || results == NULL) + return -1; + + ntoh_ptp_results(results); + + ctx.size = 2*PTP_SYNC_LOOP; + ctx.ptp = ptp; + ctx.clock = clock_context; + ctx.msg.count = 0; + ctx.msg.series_id = ptp->series_id; + tracefs_iterate_raw_events(ptp->tep, clock_context->instance, + ptp_marker_find, &ctx); + + ptp_calc_offset(clock_context, &ctx.msg, results, offset, + timestamp, &bad_probes); + +#ifdef TSYNC_DEBUG + { + char buff[256]; + int res_fd; + + sprintf(buff, "res-cid%d.txt", clock_context->remote_cid); + + res_fd = open(buff, O_WRONLY|O_APPEND, 0644); + if (res_fd > 0) { + if (*offset && *timestamp) { + sprintf(buff, "%d %lld %lld\n", + ptp->series_id, *offset, *timestamp); + write(res_fd, buff, strlen(buff)); + } + close(res_fd); + } + + printf("\n calculated offset %d: %lld, %d probes, filtered out %d\n\r", + ptp->series_id, *offset, results->count, bad_probes); + if (ptp && ptp->debug_fd > 0) { + sprintf(buff, "%lld %lld 0\n", *offset, *timestamp); + write(ptp->debug_fd, buff, strlen(buff)); + close(ptp->debug_fd); + ptp->debug_fd = -1; + } + + } +#endif + + res_offset.offset = htonll(*offset); + res_offset.ts = htonll(*timestamp); + ret = tracecmd_msg_send_time_sync(tsync->msg_handle, + TRACECMD_TIME_SYNC_PROTO_PTP, + PTP_SYNC_PKT_OFFSET, + sizeof(res_offset), + (char *)&res_offset); + + free(results); + return 0; +} + +static int ptp_clock_sync_calc(struct tracecmd_time_sync *tsync, + long long *offset, long long *timestamp) +{ + struct clock_sync_context *clock_context; + int ret; + + if (!tsync || !tsync->context) + return -1; + clock_context = (struct clock_sync_context *)tsync->context; + +#ifdef TSYNC_DEBUG + if (clock_context->is_server) { + struct ptp_clock_sync *ptp; + char buff[256]; + + ptp = (struct ptp_clock_sync *)clock_context->proto_data; + if (ptp->debug_fd > 0) + close(ptp->debug_fd); + sprintf(buff, "s-cid%d_%d.txt", + clock_context->remote_cid, ptp->series_id+1); + ptp->debug_fd = open(buff, O_CREAT|O_WRONLY|O_TRUNC, 0644); + } +#endif + + + if (clock_context->is_server) + ret = ptp_clock_server(tsync, offset, timestamp); + else + ret = ptp_clock_client(tsync, offset, timestamp); + + return ret; +} + +int ptp_clock_sync_register(void) +{ + return tracecmd_tsync_proto_register(TRACECMD_TIME_SYNC_PROTO_PTP, + TRACECMD_TIME_SYNC_PROTO_PTP_WEIGHT, + ptp_clock_sync_init, + ptp_clock_sync_free, + ptp_clock_sync_calc); + +} + +int ptp_clock_sync_unregister(void) +{ + return tracecmd_tsync_proto_unregister(TRACECMD_TIME_SYNC_PROTO_PTP); +} diff --git a/lib/trace-cmd/trace-timesync.c b/lib/trace-cmd/trace-timesync.c index 0534b14f..68d53127 100644 --- a/lib/trace-cmd/trace-timesync.c +++ b/lib/trace-cmd/trace-timesync.c @@ -46,6 +46,14 @@ static struct tsync_proto *tsync_proto_find(unsigned int proto_id) return NULL; } +/** + * tracecmd_tsync_init - Initialize the global, per task, time sync data. + */ +void tracecmd_tsync_init(void) +{ + ptp_clock_sync_register(); +} + int tracecmd_tsync_proto_register(unsigned int proto_id, int weight, int (*init)(struct tracecmd_time_sync *), int (*free)(struct tracecmd_time_sync *), diff --git a/tracecmd/trace-agent.c b/tracecmd/trace-agent.c index b5816966..2fd09dc3 100644 --- a/tracecmd/trace-agent.c +++ b/tracecmd/trace-agent.c @@ -247,6 +247,8 @@ static void agent_serve(unsigned int port) if (sd < 0) die("Failed to open vsocket"); + tracecmd_tsync_init(); + if (!get_local_cid(&cid)) printf("listening on @%u:%u\n", cid, port); diff --git a/tracecmd/trace-record.c b/tracecmd/trace-record.c index a60a5531..9b6b1945 100644 --- a/tracecmd/trace-record.c +++ b/tracecmd/trace-record.c @@ -6086,10 +6086,6 @@ static bool has_local_instances(void) return false; } -/* - * This function contains common code for the following commands: - * record, start, stream, profile. - */ static void record_trace(int argc, char **argv, struct common_record_context *ctx) { @@ -6223,12 +6219,23 @@ static void record_trace(int argc, char **argv, finalize_record_trace(ctx); } +/* + * This function contains common code for the following commands: + * record, start, stream, profile. + */ +static void record_trace_command(int argc, char **argv, + struct common_record_context *ctx) +{ + tracecmd_tsync_init(); + record_trace(argc, argv, ctx); +} + void trace_start(int argc, char **argv) { struct common_record_context ctx; parse_record_options(argc, argv, CMD_start, &ctx); - record_trace(argc, argv, &ctx); + record_trace_command(argc, argv, &ctx); exit(0); } @@ -6308,7 +6315,7 @@ void trace_stream(int argc, char **argv) struct common_record_context ctx; parse_record_options(argc, argv, CMD_stream, &ctx); - record_trace(argc, argv, &ctx); + record_trace_command(argc, argv, &ctx); exit(0); } @@ -6327,7 +6334,7 @@ void trace_profile(int argc, char **argv) if (!buffer_instances) top_instance.flags |= BUFFER_FL_PROFILE; - record_trace(argc, argv, &ctx); + record_trace_command(argc, argv, &ctx); do_trace_profile(); exit(0); } @@ -6346,7 +6353,7 @@ void trace_record(int argc, char **argv) struct common_record_context ctx; parse_record_options(argc, argv, CMD_record, &ctx); - record_trace(argc, argv, &ctx); + record_trace_command(argc, argv, &ctx); exit(0); } From patchwork Thu Feb 27 14:20:01 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: "Tzvetomir Stoyanov (VMware)" X-Patchwork-Id: 11408705 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 135D2930 for ; Thu, 27 Feb 2020 14:20:47 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.kernel.org (Postfix) with ESMTP id DC28124697 for ; Thu, 27 Feb 2020 14:20:46 +0000 (UTC) Authentication-Results: mail.kernel.org; dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b="P9CoOhPK" Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S2390034AbgB0OU3 (ORCPT ); Thu, 27 Feb 2020 09:20:29 -0500 Received: from mail-lj1-f182.google.com ([209.85.208.182]:34653 "EHLO mail-lj1-f182.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S2389753AbgB0OU2 (ORCPT ); Thu, 27 Feb 2020 09:20:28 -0500 Received: by mail-lj1-f182.google.com with SMTP id x7so3646206ljc.1 for ; Thu, 27 Feb 2020 06:20:26 -0800 (PST) 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=BqBpWvbrJyq23NGDhIETAtAQlSqS0Rq6mOlw7HCZ6Cs=; b=P9CoOhPKfyoXIX5KiqQronGqZ9qH2XTnfGW5mGbQCgyGLMbEHSI7/sm5mo+Y9iixzq FolYgZc2lS3RFRCHiLR/wh70pB/AIUF0KI0Hg51I86CQLS76mNMZO76KbIwWrbLmAAR/ aPI6i3tTRBw2BJJV6c75mxig6v0jBI8Fk7qGIgDEdMRMWLkAPPowswOQsnC2OJw6p4xW eKsHyyRL8RCsNnvkHseyMj3kISOkqKEaU3N037oNSUTkg2/qyG5rohMhgicfvpfYFITA fNnLq2IXZodsEdOp4jMQdSV3zwmYO9VHmHKQtRWW6XXQvnWq0hkjpppGUarcS5vjOURu w0Ug== 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=BqBpWvbrJyq23NGDhIETAtAQlSqS0Rq6mOlw7HCZ6Cs=; b=qde+TgY7D3ny8WhCGQm4XCeo7MVcst0z9btWIa1UcpZpwGG572SElc1m5y/IhbO4Ju f42MSzxuGhiCvPsr7R5+cmYsN03AIhB5X5Hy8/VbtHl4hJn9qAi9nkzfxTRlGEL1A3uW S5iYF5FJ6ukEWP/nOMm800PKuFmPA9ujYgmA+gMU2xiW/8/e9TBUT40G44XtsqIBDCUW xmTVbLA+NCyDOA4s1KGkYA2f7SegSQ0H522xg8ad3F8YGf5Aq0mo85SAaPq/OzsNTBgh 7Ha7nvuPMmG1vil067tKVUwrdLxh/WawjfS/XRbhm+Aa5kdsg4O1p+sDGyPJWePIM/AE 9RSg== X-Gm-Message-State: ANhLgQ0DC9sUcWSx9BMFzWgoamDLGCYXCOpDGOZJX6FdFrJWJ3rXdP2m 54lY8nPjOnyti9rcwB6G4YI= X-Google-Smtp-Source: ADFU+vuC/2BRNwBb8D61ZJHr3u/NC0ycE9XaBeU9LtskVA1qXvbS/2qSQczH+V2v9qFpwndiSi3lNw== X-Received: by 2002:a2e:94d:: with SMTP id 74mr2766129ljj.280.1582813225257; Thu, 27 Feb 2020 06:20:25 -0800 (PST) Received: from oberon.zico.biz ([83.222.187.186]) by smtp.gmail.com with ESMTPSA id l3sm3306437lja.78.2020.02.27.06.20.24 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Thu, 27 Feb 2020 06:20:24 -0800 (PST) From: "Tzvetomir Stoyanov (VMware)" To: rostedt@goodmis.org Cc: linux-trace-devel@vger.kernel.org Subject: [PATCH v20 15/15] trace-cmd: Debug scripts for PTP-like algorithm for host - guest timestamp synchronization Date: Thu, 27 Feb 2020 16:20:01 +0200 Message-Id: <20200227142001.61577-16-tz.stoyanov@gmail.com> X-Mailer: git-send-email 2.24.1 In-Reply-To: <20200227142001.61577-1-tz.stoyanov@gmail.com> References: <20200227142001.61577-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 These scripts can be used to visualise debug files, written when the PTP-like algorithm is compiled with TSYNC_DEBUG defined. The files are located in the guest machine: s-cid*.txt - For each offset calculation: host and guest clocks and calculated offset. res-cid*.txt - For each tracing session: all calculated clock offsets. tsync_hist.py plots a histogram, using data from a s-cid*.txt file: "python tsync_hist.py s-cid2_1.txt" tsync_res.py plots a line, using data from res-cid*.txt file: "python tsync_res.py res-cid2.txt" Signed-off-by: Tzvetomir Stoyanov (VMware) --- scripts/debug/tsync_hist.py | 57 +++++++++++++++++++++++++++++++++++++ scripts/debug/tsync_readme | 12 ++++++++ scripts/debug/tsync_res.py | 46 ++++++++++++++++++++++++++++++ 3 files changed, 115 insertions(+) create mode 100644 scripts/debug/tsync_hist.py create mode 100644 scripts/debug/tsync_readme create mode 100644 scripts/debug/tsync_res.py diff --git a/scripts/debug/tsync_hist.py b/scripts/debug/tsync_hist.py new file mode 100644 index 00000000..819d1e8f --- /dev/null +++ b/scripts/debug/tsync_hist.py @@ -0,0 +1,57 @@ +# SPDX-License-Identifier: GPL-2.0 +# +# Copyright (C) 2019, VMware Inc, Tzvetomir Stoyanov +# Copyright (C) 2019, VMware Inc, Yordan Karadzhov + + +import matplotlib.pyplot as plt +import matplotlib.lines as mlines +import numpy as np +import sys + +def newline(p1, p2): + ax = plt.gca() + xmin, xmax = ax.get_xbound() + + if(p2[0] == p1[0]): + xmin = xmax = p1[0] + ymin, ymax = ax.get_ybound() + else: + ymax = p1[1]+(p2[1]-p1[1])/(p2[0]-p1[0])*(xmax-p1[0]) + ymin = p1[1]+(p2[1]-p1[1])/(p2[0]-p1[0])*(xmin-p1[0]) + + l = mlines.Line2D([xmin,xmax], [ymin,ymax], color='red') + ax.add_line(l) + return l + + +data = np.loadtxt(fname = sys.argv[1]) +selected_ts = data[-1, 1] +selected_ofs = data[-1, 0] +data = data[:-1,:] + +x = data[:, 1] - data[:, 0] + +mean = x.mean() +std = x.std() + +num_bins = 500 +min = x.min() #+ .4 * (x.max() - x.min()) +max = x.max() #- .4 * (x.max() - x.min()) +bins = np.linspace(min, max, num_bins, endpoint = False, dtype=int) + +fig, ax = plt.subplots() + +# the histogram of the data +n, bins, patches = ax.hist(x, bins, histtype=u'step'); + +ax.set_xlabel('clock offset [$\mu$s]') +ax.set_ylabel('entries') +ax.set_title("$\sigma$=%i" % std) + +x1, y1 = [selected_ofs, min], [selected_ofs, max] +newline(x1, y1) + +# Tweak spacing to prevent clipping of ylabel +fig.tight_layout() +plt.show() diff --git a/scripts/debug/tsync_readme b/scripts/debug/tsync_readme new file mode 100644 index 00000000..f3ebb25d --- /dev/null +++ b/scripts/debug/tsync_readme @@ -0,0 +1,12 @@ +PTP-like algorithm debug +======================== + +tsync_*.py scripts can be used to visualise debug files, written when the PTP-like algorithm +is compiled with TSYNC_DEBUG defined. The files are located in the guest machine: + s-cid*.txt - For each offset calculation: host and guest clocks and calculated offset. + res-cid*.txt - For each tracing session: all calculated clock offsets. + +tsync_hist.py plots a histogram, using data from a s-cid*.txt file: + "python tsync_hist.py s-cid2_1.txt" +tsync_res.py plots a line, using data from res-cid*.txt file: + "python tsync_res.py res-cid2.txt" diff --git a/scripts/debug/tsync_res.py b/scripts/debug/tsync_res.py new file mode 100644 index 00000000..7d109863 --- /dev/null +++ b/scripts/debug/tsync_res.py @@ -0,0 +1,46 @@ +# SPDX-License-Identifier: GPL-2.0 +# +# Copyright (C) 2019, VMware Inc, Tzvetomir Stoyanov +# Copyright (C) 2019, VMware Inc, Yordan Karadzhov + + +import matplotlib.pyplot as plt +import matplotlib.lines as mlines +import numpy as np +import sys + +def newline(p1, p2): + ax = plt.gca() + xmin, xmax = ax.get_xbound() + + if(p2[0] == p1[0]): + xmin = xmax = p1[0] + ymin, ymax = ax.get_ybound() + else: + ymax = p1[1]+(p2[1]-p1[1])/(p2[0]-p1[0])*(xmax-p1[0]) + ymin = p1[1]+(p2[1]-p1[1])/(p2[0]-p1[0])*(xmin-p1[0]) + + l = mlines.Line2D([xmin,xmax], [ymin,ymax], color='red') + ax.add_line(l) + return l + +data = np.loadtxt(fname = sys.argv[1]) +x = data[:, 0] +y = data[:, 1] + +fig, ax = plt.subplots() + +ax.set_xlabel('samples (t)') +ax.set_ylabel('clock offset') +ax.set_title("$\delta$=%i ns" % (max(y) - min(y))) + +l = mlines.Line2D(x, y) +ax.add_line(l) +ax.set_xlim(min(x), max(x)) +ax.set_ylim(min(y), max(y) ) + +print(min(y), max(y), max(y) - min(y)) + +# Tweak spacing to prevent clipping of ylabel +fig.tight_layout() +plt.show()