summaryrefslogtreecommitdiff
path: root/trace2
diff options
context:
space:
mode:
Diffstat (limited to 'trace2')
-rw-r--r--trace2/tr2_dst.c120
-rw-r--r--trace2/tr2_dst.h1
-rw-r--r--trace2/tr2_sysenv.c3
-rw-r--r--trace2/tr2_sysenv.h2
-rw-r--r--trace2/tr2_tgt_event.c36
-rw-r--r--trace2/tr2_tgt_normal.c37
-rw-r--r--trace2/tr2_tgt_perf.c91
7 files changed, 211 insertions, 79 deletions
diff --git a/trace2/tr2_dst.c b/trace2/tr2_dst.c
index 5dda0ca1cd..ae052a07fe 100644
--- a/trace2/tr2_dst.c
+++ b/trace2/tr2_dst.c
@@ -8,6 +8,19 @@
*/
#define MAX_AUTO_ATTEMPTS 10
+/*
+ * Sentinel file used to detect when we should discard new traces to avoid
+ * writing too many trace files to a directory.
+ */
+#define DISCARD_SENTINEL_NAME "git-trace2-discard"
+
+/*
+ * When set to zero, disables directory file count checks. Otherwise, controls
+ * how many files we can write to a directory before entering discard mode.
+ * This can be overridden via the TR2_SYSENV_MAX_FILES setting.
+ */
+static int tr2env_max_files = 0;
+
static int tr2_dst_want_warning(void)
{
static int tr2env_dst_debug = -1;
@@ -32,9 +45,75 @@ void tr2_dst_trace_disable(struct tr2_dst *dst)
dst->need_close = 0;
}
+/*
+ * Check to make sure we're not overloading the target directory with too many
+ * files. First get the threshold (if present) from the config or envvar. If
+ * it's zero or unset, disable this check. Next check for the presence of a
+ * sentinel file, then check file count.
+ *
+ * Returns 0 if tracing should proceed as normal. Returns 1 if the sentinel file
+ * already exists, which means tracing should be disabled. Returns -1 if there
+ * are too many files but there was no sentinel file, which means we have
+ * created and should write traces to the sentinel file.
+ *
+ * We expect that some trace processing system is gradually collecting files
+ * from the target directory; after it removes the sentinel file we'll start
+ * writing traces again.
+ */
+static int tr2_dst_too_many_files(struct tr2_dst *dst, const char *tgt_prefix)
+{
+ int file_count = 0, max_files = 0, ret = 0;
+ const char *max_files_var;
+ DIR *dirp;
+ struct strbuf path = STRBUF_INIT, sentinel_path = STRBUF_INIT;
+ struct stat statbuf;
+
+ /* Get the config or envvar and decide if we should continue this check */
+ max_files_var = tr2_sysenv_get(TR2_SYSENV_MAX_FILES);
+ if (max_files_var && *max_files_var && ((max_files = atoi(max_files_var)) >= 0))
+ tr2env_max_files = max_files;
+
+ if (!tr2env_max_files) {
+ ret = 0;
+ goto cleanup;
+ }
+
+ strbuf_addstr(&path, tgt_prefix);
+ if (!is_dir_sep(path.buf[path.len - 1])) {
+ strbuf_addch(&path, '/');
+ }
+
+ /* check sentinel */
+ strbuf_addbuf(&sentinel_path, &path);
+ strbuf_addstr(&sentinel_path, DISCARD_SENTINEL_NAME);
+ if (!stat(sentinel_path.buf, &statbuf)) {
+ ret = 1;
+ goto cleanup;
+ }
+
+ /* check file count */
+ dirp = opendir(path.buf);
+ while (file_count < tr2env_max_files && dirp && readdir(dirp))
+ file_count++;
+ if (dirp)
+ closedir(dirp);
+
+ if (file_count >= tr2env_max_files) {
+ dst->too_many_files = 1;
+ dst->fd = open(sentinel_path.buf, O_WRONLY | O_CREAT | O_EXCL, 0666);
+ ret = -1;
+ goto cleanup;
+ }
+
+cleanup:
+ strbuf_release(&path);
+ strbuf_release(&sentinel_path);
+ return ret;
+}
+
static int tr2_dst_try_auto_path(struct tr2_dst *dst, const char *tgt_prefix)
{
- int fd;
+ int too_many_files;
const char *last_slash, *sid = tr2_sid_get();
struct strbuf path = STRBUF_INIT;
size_t base_path_len;
@@ -50,18 +129,29 @@ static int tr2_dst_try_auto_path(struct tr2_dst *dst, const char *tgt_prefix)
strbuf_addstr(&path, sid);
base_path_len = path.len;
- for (attempt_count = 0; attempt_count < MAX_AUTO_ATTEMPTS; attempt_count++) {
- if (attempt_count > 0) {
- strbuf_setlen(&path, base_path_len);
- strbuf_addf(&path, ".%d", attempt_count);
+ too_many_files = tr2_dst_too_many_files(dst, tgt_prefix);
+ if (!too_many_files) {
+ for (attempt_count = 0; attempt_count < MAX_AUTO_ATTEMPTS; attempt_count++) {
+ if (attempt_count > 0) {
+ strbuf_setlen(&path, base_path_len);
+ strbuf_addf(&path, ".%d", attempt_count);
+ }
+
+ dst->fd = open(path.buf, O_WRONLY | O_CREAT | O_EXCL, 0666);
+ if (dst->fd != -1)
+ break;
}
-
- fd = open(path.buf, O_WRONLY | O_CREAT | O_EXCL, 0666);
- if (fd != -1)
- break;
+ } else if (too_many_files == 1) {
+ strbuf_release(&path);
+ if (tr2_dst_want_warning())
+ warning("trace2: not opening %s trace file due to too "
+ "many files in target directory %s",
+ tr2_sysenv_display_name(dst->sysenv_var),
+ tgt_prefix);
+ return 0;
}
- if (fd == -1) {
+ if (dst->fd == -1) {
if (tr2_dst_want_warning())
warning("trace2: could not open '%.*s' for '%s' tracing: %s",
(int) base_path_len, path.buf,
@@ -75,7 +165,6 @@ static int tr2_dst_try_auto_path(struct tr2_dst *dst, const char *tgt_prefix)
strbuf_release(&path);
- dst->fd = fd;
dst->need_close = 1;
dst->initialized = 1;
@@ -215,13 +304,8 @@ connected:
static void tr2_dst_malformed_warning(struct tr2_dst *dst,
const char *tgt_value)
{
- struct strbuf buf = STRBUF_INIT;
-
- strbuf_addf(&buf, "trace2: unknown value for '%s': '%s'",
- tr2_sysenv_display_name(dst->sysenv_var), tgt_value);
- warning("%s", buf.buf);
-
- strbuf_release(&buf);
+ warning("trace2: unknown value for '%s': '%s'",
+ tr2_sysenv_display_name(dst->sysenv_var), tgt_value);
}
int tr2_dst_get_trace_fd(struct tr2_dst *dst)
diff --git a/trace2/tr2_dst.h b/trace2/tr2_dst.h
index 3adf3bac13..b1a8c144e0 100644
--- a/trace2/tr2_dst.h
+++ b/trace2/tr2_dst.h
@@ -9,6 +9,7 @@ struct tr2_dst {
int fd;
unsigned int initialized : 1;
unsigned int need_close : 1;
+ unsigned int too_many_files : 1;
};
/*
diff --git a/trace2/tr2_sysenv.c b/trace2/tr2_sysenv.c
index 5958cfc424..3c3792eca2 100644
--- a/trace2/tr2_sysenv.c
+++ b/trace2/tr2_sysenv.c
@@ -49,6 +49,9 @@ static struct tr2_sysenv_entry tr2_sysenv_settings[] = {
"trace2.perftarget" },
[TR2_SYSENV_PERF_BRIEF] = { "GIT_TRACE2_PERF_BRIEF",
"trace2.perfbrief" },
+
+ [TR2_SYSENV_MAX_FILES] = { "GIT_TRACE2_MAX_FILES",
+ "trace2.maxfiles" },
};
/* clang-format on */
diff --git a/trace2/tr2_sysenv.h b/trace2/tr2_sysenv.h
index 8dd82a7a56..d4364a7b85 100644
--- a/trace2/tr2_sysenv.h
+++ b/trace2/tr2_sysenv.h
@@ -24,6 +24,8 @@ enum tr2_sysenv_variable {
TR2_SYSENV_PERF,
TR2_SYSENV_PERF_BRIEF,
+ TR2_SYSENV_MAX_FILES,
+
TR2_SYSENV_MUST_BE_LAST
};
diff --git a/trace2/tr2_tgt_event.c b/trace2/tr2_tgt_event.c
index c2852d1bd2..6353e8ad91 100644
--- a/trace2/tr2_tgt_event.c
+++ b/trace2/tr2_tgt_event.c
@@ -10,16 +10,17 @@
#include "trace2/tr2_tgt.h"
#include "trace2/tr2_tls.h"
-static struct tr2_dst tr2dst_event = { TR2_SYSENV_EVENT, 0, 0, 0 };
+static struct tr2_dst tr2dst_event = { TR2_SYSENV_EVENT, 0, 0, 0, 0 };
/*
- * The version number of the JSON data generated by the EVENT target
- * in this source file. Update this if you make a significant change
- * to the JSON fields or message structure. You probably do not need
- * to update this if you just add another call to one of the existing
- * TRACE2 API methods.
+ * The version number of the JSON data generated by the EVENT target in this
+ * source file. The version should be incremented if new event types are added,
+ * if existing fields are removed, or if there are significant changes in
+ * interpretation of existing events or fields. Smaller changes, such as adding
+ * a new field to an existing event, do not require an increment to the EVENT
+ * format version.
*/
-#define TR2_EVENT_VERSION "1"
+#define TR2_EVENT_VERSION "2"
/*
* Region nesting limit for messages written to the event target.
@@ -107,6 +108,19 @@ static void event_fmt_prepare(const char *event_name, const char *file,
jw_object_intmax(jw, "repo", repo->trace2_repo_id);
}
+static void fn_too_many_files_fl(const char *file, int line)
+{
+ const char *event_name = "too_many_files";
+ struct json_writer jw = JSON_WRITER_INIT;
+
+ jw_object_begin(&jw, 0);
+ event_fmt_prepare(event_name, file, line, NULL, &jw);
+ jw_end(&jw);
+
+ tr2_dst_write_line(&tr2dst_event, &jw.json);
+ jw_release(&jw);
+}
+
static void fn_version_fl(const char *file, int line)
{
const char *event_name = "version";
@@ -120,6 +134,9 @@ static void fn_version_fl(const char *file, int line)
tr2_dst_write_line(&tr2dst_event, &jw.json);
jw_release(&jw);
+
+ if (tr2dst_event.too_many_files)
+ fn_too_many_files_fl(file, line);
}
static void fn_start_fl(const char *file, int line,
@@ -205,11 +222,6 @@ static void maybe_add_string_va(struct json_writer *jw, const char *field_name,
strbuf_release(&buf);
return;
}
-
- if (fmt && *fmt) {
- jw_object_string(jw, field_name, fmt);
- return;
- }
}
static void fn_error_va_fl(const char *file, int line, const char *fmt,
diff --git a/trace2/tr2_tgt_normal.c b/trace2/tr2_tgt_normal.c
index 00b116d797..31b602c171 100644
--- a/trace2/tr2_tgt_normal.c
+++ b/trace2/tr2_tgt_normal.c
@@ -9,7 +9,7 @@
#include "trace2/tr2_tgt.h"
#include "trace2/tr2_tls.h"
-static struct tr2_dst tr2dst_normal = { TR2_SYSENV_NORMAL, 0, 0, 0 };
+static struct tr2_dst tr2dst_normal = { TR2_SYSENV_NORMAL, 0, 0, 0, 0 };
/*
* Use the TR2_SYSENV_NORMAL_BRIEF setting to omit the "<time> <file>:<line>"
@@ -87,7 +87,7 @@ static void fn_start_fl(const char *file, int line,
struct strbuf buf_payload = STRBUF_INIT;
strbuf_addstr(&buf_payload, "start ");
- sq_quote_argv_pretty(&buf_payload, argv);
+ sq_append_quote_argv_pretty(&buf_payload, argv);
normal_io_write_fl(file, line, &buf_payload);
strbuf_release(&buf_payload);
}
@@ -135,11 +135,6 @@ static void maybe_append_string_va(struct strbuf *buf, const char *fmt,
va_end(copy_ap);
return;
}
-
- if (fmt && *fmt) {
- strbuf_addstr(buf, fmt);
- return;
- }
}
static void fn_error_va_fl(const char *file, int line, const char *fmt,
@@ -147,8 +142,11 @@ static void fn_error_va_fl(const char *file, int line, const char *fmt,
{
struct strbuf buf_payload = STRBUF_INIT;
- strbuf_addstr(&buf_payload, "error ");
- maybe_append_string_va(&buf_payload, fmt, ap);
+ strbuf_addstr(&buf_payload, "error");
+ if (fmt && *fmt) {
+ strbuf_addch(&buf_payload, ' ');
+ maybe_append_string_va(&buf_payload, fmt, ap);
+ }
normal_io_write_fl(file, line, &buf_payload);
strbuf_release(&buf_payload);
}
@@ -188,8 +186,8 @@ static void fn_alias_fl(const char *file, int line, const char *alias,
{
struct strbuf buf_payload = STRBUF_INIT;
- strbuf_addf(&buf_payload, "alias %s ->", alias);
- sq_quote_argv_pretty(&buf_payload, argv);
+ strbuf_addf(&buf_payload, "alias %s -> ", alias);
+ sq_append_quote_argv_pretty(&buf_payload, argv);
normal_io_write_fl(file, line, &buf_payload);
strbuf_release(&buf_payload);
}
@@ -200,12 +198,12 @@ static void fn_child_start_fl(const char *file, int line,
{
struct strbuf buf_payload = STRBUF_INIT;
- strbuf_addf(&buf_payload, "child_start[%d] ", cmd->trace2_child_id);
+ strbuf_addf(&buf_payload, "child_start[%d]", cmd->trace2_child_id);
if (cmd->dir) {
- strbuf_addstr(&buf_payload, " cd");
+ strbuf_addstr(&buf_payload, " cd ");
sq_quote_buf_pretty(&buf_payload, cmd->dir);
- strbuf_addstr(&buf_payload, "; ");
+ strbuf_addstr(&buf_payload, ";");
}
/*
@@ -213,9 +211,10 @@ static void fn_child_start_fl(const char *file, int line,
* See trace_add_env() in run-command.c as used by original trace.c
*/
+ strbuf_addch(&buf_payload, ' ');
if (cmd->git_cmd)
- strbuf_addstr(&buf_payload, "git");
- sq_quote_argv_pretty(&buf_payload, cmd->argv);
+ strbuf_addstr(&buf_payload, "git ");
+ sq_append_quote_argv_pretty(&buf_payload, cmd->argv);
normal_io_write_fl(file, line, &buf_payload);
strbuf_release(&buf_payload);
@@ -240,9 +239,11 @@ static void fn_exec_fl(const char *file, int line, uint64_t us_elapsed_absolute,
struct strbuf buf_payload = STRBUF_INIT;
strbuf_addf(&buf_payload, "exec[%d] ", exec_id);
- if (exe)
+ if (exe) {
strbuf_addstr(&buf_payload, exe);
- sq_quote_argv_pretty(&buf_payload, argv);
+ strbuf_addch(&buf_payload, ' ');
+ }
+ sq_append_quote_argv_pretty(&buf_payload, argv);
normal_io_write_fl(file, line, &buf_payload);
strbuf_release(&buf_payload);
}
diff --git a/trace2/tr2_tgt_perf.c b/trace2/tr2_tgt_perf.c
index ea0cbbe13e..ffac8029ad 100644
--- a/trace2/tr2_tgt_perf.c
+++ b/trace2/tr2_tgt_perf.c
@@ -11,7 +11,7 @@
#include "trace2/tr2_tgt.h"
#include "trace2/tr2_tls.h"
-static struct tr2_dst tr2dst_perf = { TR2_SYSENV_PERF, 0, 0, 0 };
+static struct tr2_dst tr2dst_perf = { TR2_SYSENV_PERF, 0, 0, 0, 0 };
/*
* Use TR2_SYSENV_PERF_BRIEF to omit the "<time> <file>:<line>"
@@ -21,10 +21,10 @@ static struct tr2_dst tr2dst_perf = { TR2_SYSENV_PERF, 0, 0, 0 };
*/
static int tr2env_perf_be_brief;
-#define TR2FMT_PERF_FL_WIDTH (50)
+#define TR2FMT_PERF_FL_WIDTH (28)
#define TR2FMT_PERF_MAX_EVENT_NAME (12)
-#define TR2FMT_PERF_REPO_WIDTH (4)
-#define TR2FMT_PERF_CATEGORY_WIDTH (10)
+#define TR2FMT_PERF_REPO_WIDTH (3)
+#define TR2FMT_PERF_CATEGORY_WIDTH (12)
#define TR2_DOTS_BUFFER_SIZE (100)
#define TR2_INDENT (2)
@@ -79,17 +79,36 @@ static void perf_fmt_prepare(const char *event_name,
if (!tr2env_perf_be_brief) {
struct tr2_tbuf tb_now;
+ size_t fl_end_col;
tr2_tbuf_local_time(&tb_now);
strbuf_addstr(buf, tb_now.buf);
strbuf_addch(buf, ' ');
- if (file && *file)
- strbuf_addf(buf, "%s:%d ", file, line);
- while (buf->len < TR2FMT_PERF_FL_WIDTH)
+ fl_end_col = buf->len + TR2FMT_PERF_FL_WIDTH;
+
+ if (file && *file) {
+ struct strbuf buf_fl = STRBUF_INIT;
+
+ strbuf_addf(&buf_fl, "%s:%d", file, line);
+
+ if (buf_fl.len <= TR2FMT_PERF_FL_WIDTH)
+ strbuf_addbuf(buf, &buf_fl);
+ else {
+ size_t avail = TR2FMT_PERF_FL_WIDTH - 3;
+ strbuf_addstr(buf, "...");
+ strbuf_add(buf,
+ &buf_fl.buf[buf_fl.len - avail],
+ avail);
+ }
+
+ strbuf_release(&buf_fl);
+ }
+
+ while (buf->len < fl_end_col)
strbuf_addch(buf, ' ');
- strbuf_addstr(buf, "| ");
+ strbuf_addstr(buf, " | ");
}
strbuf_addf(buf, "d%d | ", tr2_sid_depth());
@@ -102,7 +121,7 @@ static void perf_fmt_prepare(const char *event_name,
strbuf_addf(buf, "r%d ", repo->trace2_repo_id);
while (buf->len < len)
strbuf_addch(buf, ' ');
- strbuf_addstr(buf, "| ");
+ strbuf_addstr(buf, " | ");
if (p_us_elapsed_absolute)
strbuf_addf(buf, "%9.6f | ",
@@ -116,8 +135,8 @@ static void perf_fmt_prepare(const char *event_name,
else
strbuf_addf(buf, "%9s | ", " ");
- strbuf_addf(buf, "%-*s | ", TR2FMT_PERF_CATEGORY_WIDTH,
- (category ? category : ""));
+ strbuf_addf(buf, "%-*.*s | ", TR2FMT_PERF_CATEGORY_WIDTH,
+ TR2FMT_PERF_CATEGORY_WIDTH, (category ? category : ""));
if (ctx->nr_open_regions > 0) {
int len_indent = TR2_INDENT_LENGTH(ctx);
@@ -165,7 +184,7 @@ static void fn_start_fl(const char *file, int line,
const char *event_name = "start";
struct strbuf buf_payload = STRBUF_INIT;
- sq_quote_argv_pretty(&buf_payload, argv);
+ sq_append_quote_argv_pretty(&buf_payload, argv);
perf_io_write_fl(file, line, event_name, NULL, &us_elapsed_absolute,
NULL, NULL, &buf_payload);
@@ -220,11 +239,6 @@ static void maybe_append_string_va(struct strbuf *buf, const char *fmt,
va_end(copy_ap);
return;
}
-
- if (fmt && *fmt) {
- strbuf_addstr(buf, fmt);
- return;
- }
}
static void fn_error_va_fl(const char *file, int line, const char *fmt,
@@ -285,8 +299,9 @@ static void fn_alias_fl(const char *file, int line, const char *alias,
const char *event_name = "alias";
struct strbuf buf_payload = STRBUF_INIT;
- strbuf_addf(&buf_payload, "alias:%s argv:", alias);
- sq_quote_argv_pretty(&buf_payload, argv);
+ strbuf_addf(&buf_payload, "alias:%s argv:[", alias);
+ sq_append_quote_argv_pretty(&buf_payload, argv);
+ strbuf_addch(&buf_payload, ']');
perf_io_write_fl(file, line, event_name, NULL, NULL, NULL, NULL,
&buf_payload);
@@ -315,10 +330,14 @@ static void fn_child_start_fl(const char *file, int line,
sq_quote_buf_pretty(&buf_payload, cmd->dir);
}
- strbuf_addstr(&buf_payload, " argv:");
- if (cmd->git_cmd)
- strbuf_addstr(&buf_payload, " git");
- sq_quote_argv_pretty(&buf_payload, cmd->argv);
+ strbuf_addstr(&buf_payload, " argv:[");
+ if (cmd->git_cmd) {
+ strbuf_addstr(&buf_payload, "git");
+ if (cmd->argv[0])
+ strbuf_addch(&buf_payload, ' ');
+ }
+ sq_append_quote_argv_pretty(&buf_payload, cmd->argv);
+ strbuf_addch(&buf_payload, ']');
perf_io_write_fl(file, line, event_name, NULL, &us_elapsed_absolute,
NULL, NULL, &buf_payload);
@@ -369,10 +388,14 @@ static void fn_exec_fl(const char *file, int line, uint64_t us_elapsed_absolute,
struct strbuf buf_payload = STRBUF_INIT;
strbuf_addf(&buf_payload, "id:%d ", exec_id);
- strbuf_addstr(&buf_payload, "argv:");
- if (exe)
- strbuf_addf(&buf_payload, " %s", exe);
- sq_quote_argv_pretty(&buf_payload, argv);
+ strbuf_addstr(&buf_payload, "argv:[");
+ if (exe) {
+ strbuf_addstr(&buf_payload, exe);
+ if (argv[0])
+ strbuf_addch(&buf_payload, ' ');
+ }
+ sq_append_quote_argv_pretty(&buf_payload, argv);
+ strbuf_addch(&buf_payload, ']');
perf_io_write_fl(file, line, event_name, NULL, &us_elapsed_absolute,
NULL, NULL, &buf_payload);
@@ -433,8 +456,11 @@ static void fn_region_enter_printf_va_fl(const char *file, int line,
struct strbuf buf_payload = STRBUF_INIT;
if (label)
- strbuf_addf(&buf_payload, "label:%s ", label);
- maybe_append_string_va(&buf_payload, fmt, ap);
+ strbuf_addf(&buf_payload, "label:%s", label);
+ if (fmt && *fmt) {
+ strbuf_addch(&buf_payload, ' ');
+ maybe_append_string_va(&buf_payload, fmt, ap);
+ }
perf_io_write_fl(file, line, event_name, repo, &us_elapsed_absolute,
NULL, category, &buf_payload);
@@ -450,8 +476,11 @@ static void fn_region_leave_printf_va_fl(
struct strbuf buf_payload = STRBUF_INIT;
if (label)
- strbuf_addf(&buf_payload, "label:%s ", label);
- maybe_append_string_va(&buf_payload, fmt, ap);
+ strbuf_addf(&buf_payload, "label:%s", label);
+ if (fmt && *fmt) {
+ strbuf_addch(&buf_payload, ' ' );
+ maybe_append_string_va(&buf_payload, fmt, ap);
+ }
perf_io_write_fl(file, line, event_name, repo, &us_elapsed_absolute,
&us_elapsed_region, category, &buf_payload);