From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.2 (2018-09-13) on dcvr.yhbt.net X-Spam-Level: X-Spam-ASN: X-Spam-Status: No, score=-4.0 required=3.0 tests=ALL_TRUSTED,AWL,BAYES_00, DKIM_SIGNED,DKIM_VALID,DKIM_VALID_AU,DKIM_VALID_EF shortcircuit=no autolearn=ham autolearn_force=no version=3.4.2 Received: from localhost (dcvr.yhbt.net [127.0.0.1]) by dcvr.yhbt.net (Postfix) with ESMTP id 7C45D1F9FC for ; Mon, 19 Dec 2022 11:19:23 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=80x24.org; s=selector1; t=1671448763; bh=2mUjgxTes7ZfPe/FFVdXqnmk08akNegSnd+3A1j/8G8=; h=From:To:Subject:Date:In-Reply-To:References:From; b=C5Ca1UGW19GR6TKHFzEIP3EXJryeSOGS6AmAJYSUAdI5oDTqhE7zMleJRob1lmYcV XxfWOE6aYZj7YAmNs4EvkG+GX6IdqpqjrQybx6X537zP7PZKoSP4Ke6wBZbuKZeUpe egG8qXpsQSzgDieIiExfBapmDZ4pt/qfhgnXf1fA= From: Eric Wong To: mwrap-perl@80x24.org Subject: [PATCH 2/7] core: shrink src_loc by another 8 bytes on x86-64 Date: Mon, 19 Dec 2022 11:19:17 +0000 Message-Id: <20221219111922.1079128-3-e@80x24.org> In-Reply-To: <20221219111922.1079128-1-e@80x24.org> References: <20221219111922.1079128-1-e@80x24.org> MIME-Version: 1.0 Content-Transfer-Encoding: 8bit List-Id: lineno shouldn't need more than 24-bits (or >= 16.7 million). Our bt_len is capped at 32, and nobody should ever need to care about tracking allocations if call stack depths exceed 256. --- Mwrap.xs | 4 ++-- httpd.h | 6 ++--- mwrap_core.h | 62 +++++++++++++++++++++++++++++++++------------------- 3 files changed, 45 insertions(+), 27 deletions(-) diff --git a/Mwrap.xs b/Mwrap.xs index 846d89d..846d0cb 100644 --- a/Mwrap.xs +++ b/Mwrap.xs @@ -19,10 +19,10 @@ static SV *location_string(struct src_loc *l) if (l->f) { sv_catpv(ret, l->f->fn); - if (l->lineno == UINT_MAX) + if (l->lineno == U24_MAX) sv_catpvs(ret, ":-"); else - sv_catpvf(ret, ":%zu", l->lineno); + sv_catpvf(ret, ":%u", l->lineno); } if (l->bt_len) { AUTO_FREE char **s = bt_syms(l->bt, l->bt_len); diff --git a/httpd.h b/httpd.h index 8e58286..eddea97 100644 --- a/httpd.h +++ b/httpd.h @@ -473,10 +473,10 @@ static off_t write_loc_name(FILE *fp, const struct src_loc *l) } if (l->f) { fputs(l->f->fn, fp); - if (l->lineno == UINT_MAX) + if (l->lineno == U24_MAX) FPUTS(":-", fp); else - fprintf(fp, ":%zu", l->lineno); + fprintf(fp, ":%u", l->lineno); } if (l->bt_len) { AUTO_FREE char **s = bt_syms(l->bt, l->bt_len); @@ -703,7 +703,7 @@ static enum mw_qev each_gt(struct mw_h1 *h1, struct mw_h1req *h1r, hsl->live, hsl->mean_life, hsl->max_life); FPUTS("sl->f, + write_b64_url(fp, src_loc_hash_tip(hsl->sl), src_loc_hash_len(hsl->sl)); FPUTS("\">", fp); diff --git a/mwrap_core.h b/mwrap_core.h index 7be0a7a..7f52f39 100644 --- a/mwrap_core.h +++ b/mwrap_core.h @@ -61,6 +61,8 @@ typedef void COP; # include "jhash.h" #endif +#define U24_MAX (1U << 24) + /* * Perl doesn't have a GC the same way (C) Ruby does, so no GC count. * Instead, the relative age of an object is the number of total bytes @@ -166,18 +168,15 @@ struct src_loc { struct cds_lfht_node hnode; /* <=> totals table */ struct cds_list_head allocs; /* <=> alloc_hdr.node */ uint32_t loc_hash; - uint32_t bt_len; + uint8_t bt_len; /* next 3 fields contiguous for hash_src_loc(): */ + unsigned lineno:24; /* nobody should have >=16.7 LoC in one file */ struct src_file *f; - /* .lineno only needs `unsigned', but is size_t for alignment */ - size_t lineno; void *bt[]; -}; +} __attribute__((packed,aligned(8))); -#ifdef static_assert -static_assert(sizeof(struct src_file *) == sizeof(size_t), - "size_t is the same size as a pointer"); -#endif +/* sizeof() doesn't work on bitfields */ +#define SIZEOF_LINENO (size_t)(24 / 8) /* * Every allocation has this in the header, maintain alignment with malloc @@ -216,13 +215,13 @@ union stk_bt { * thing. */ #ifdef static_assert -static_assert(offsetof(struct src_loc, lineno) + sizeof(void *) == +static_assert(offsetof(struct src_loc, f) + sizeof(void *) == offsetof(struct src_loc, bt), "bt lineno is is bt[-1]"); #endif static void **bt_dst(union stk_bt *bt) { - return (void **)&bt->sl.lineno; + return (void **)&bt->sl.f; } static struct alloc_hdr *ptr2hdr(void *p) @@ -247,7 +246,12 @@ static size_t bt_bytelen(const struct src_loc *l) static size_t src_loc_hash_len(const struct src_loc *l) { - return sizeof(l->f) + sizeof(l->lineno) + + bt_bytelen(l); + return sizeof(l->f) + SIZEOF_LINENO + bt_bytelen(l); +} + +static void *src_loc_hash_tip(const struct src_loc *l) +{ + return (void *)((uintptr_t)&l->bt_len + sizeof(l->bt_len)); } static int loc_eq(struct cds_lfht_node *node, const void *key) @@ -258,7 +262,8 @@ static int loc_eq(struct cds_lfht_node *node, const void *key) existing = caa_container_of(node, struct src_loc, hnode); return (k->bt_len == existing->bt_len && - !memcmp(&k->f, &existing->f, src_loc_hash_len(k))); + !memcmp(src_loc_hash_tip(k), src_loc_hash_tip(existing), + src_loc_hash_len(k))); } static int fn_eq(struct cds_lfht_node *node, const void *key) @@ -356,7 +361,7 @@ static uint32_t do_hash(const void *p, size_t len) static void hash_src_loc(struct src_loc *l) { - l->loc_hash = do_hash(&l->f, src_loc_hash_len(l)); + l->loc_hash = do_hash(src_loc_hash_tip(l), src_loc_hash_len(l)); } static struct src_file *src_file_get(struct cds_lfht *t, struct src_file *k, @@ -401,6 +406,15 @@ static struct src_loc *assign_line(size_t size, const COP *cop, size_t len = strlen(fn); if (len >= PATH_MAX) len = PATH_MAX - 1; + + if (lineno == UINT_MAX) { /* NOLINE in Perl is UINT_MAX */ + lineno = U24_MAX; + } else if (lineno > U24_MAX) { + fprintf(stderr, + "%s:%u line number exceeds limit (%u), capped\n", + fn, lineno, U24_MAX); + lineno = U24_MAX; + } again: f = src_file_get(t, &sf.sf, fn, len); if (!f) { /* doesn't exist, add a new one */ @@ -417,6 +431,7 @@ again: goto again; } } + sl->total = size; sl->f = f; sl->lineno = lineno; @@ -767,7 +782,7 @@ static void *dump_to_file(struct dump_arg *a) fprintf(a->fp, "%16zu %12zu %s\n", l->total, l->allocations, s[0]); } else { - fprintf(a->fp, "%16zu %12zu %s:%zu\n", + fprintf(a->fp, "%16zu %12zu %s:%u\n", l->total, l->allocations, l->f->fn, l->lineno); } } @@ -812,7 +827,7 @@ static struct src_loc *src_loc_lookup(const char *str, size_t len) size_t fn_len = c - str; c++; if (*c == '-') { - lineno = UINT_MAX; + lineno = U24_MAX; } else { lineno = 0; for (; c < end; c++) { @@ -821,6 +836,8 @@ static struct src_loc *src_loc_lookup(const char *str, size_t len) lineno *= 10; lineno += (*c - '0'); } + if (lineno > U24_MAX) + return NULL; } rcu_read_lock(); struct src_file *f = src_file_get(t, &sf.sf, str, fn_len); @@ -953,19 +970,20 @@ static struct src_loc *mwrap_get(const char *str, size_t len) static struct src_loc *mwrap_get_bin(const char *buf, size_t len) { - if ((len % sizeof(void *)) == 0 && len >= (2 * sizeof(void *))) { - union stk_bt k; + static const size_t min_len = sizeof(struct src_file *) + SIZEOF_LINENO; + + if (len >= min_len && ((len - min_len) % sizeof(void *)) == 0) { struct cds_lfht *t = CMM_LOAD_SHARED(totals); if (!t) return NULL; - k.sl.bt_len = len / sizeof(void *); - k.sl.bt_len -= 2; /* lineno + src_file *f */ + union stk_bt k; + size_t bt_len = (len - min_len) / sizeof(void *); - if (k.sl.bt_len > MWRAP_BT_MAX) + if (bt_len > MWRAP_BT_MAX) return NULL; + k.sl.bt_len = bt_len; - memcpy(&k.sl.f, buf, len); - + memcpy(src_loc_hash_tip(&k.sl), buf, len); hash_src_loc(&k.sl); rcu_read_lock(); struct src_loc *l = src_loc_get(t, &k.sl);