浏览代码

Add some tweaks for the Lwan framework (#5297)

* Lwan: Use a newer Lwan for the benchmarks

The new version has a fast memory allocator that benefits the Fortunes
benchmark slightly, alongside a few other minor changes.  Minor details
in the benchmark harness have been fixed/tweaked as well.

* Lwan: Build Lwan with auto-profile information gathered with AutoFDO

* Lwan: Use mimalloc as memory allocator

* Lwan: Build without PLT/use immediate binding/relro
Leandro A. F. Pereira 5 年之前
父节点
当前提交
df8e549b80

+ 5 - 3
frameworks/C/lwan/Makefile

@@ -1,12 +1,14 @@
 .PHONY: all
 
-CFLAGS = -mtune=native -march=native -O3 -flto -ffat-lto-objects -DNDEBUG \
+CFLAGS = -mtune=native -march=native -O3 -fno-plt -flto -ffat-lto-objects -DNDEBUG \
 	-include /lwan/build/lwan-build-config.h \
 	-I /lwan/src/lib \
 	`pkg-config mariadb --cflags` \
-	`pkg-config sqlite3 --cflags`
+	`pkg-config sqlite3 --cflags` \
+	-fauto-profile=/lwan/src/gcda/techempower.gcov
 
-LDFLAGS = -mtune=native -march=native -O3 -flto -ffat-lto-objects \
+LDFLAGS = -mtune=native -march=native -O3 -flto -ffat-lto-objects -Wl,-z,now,-z,relro \
+	/usr/local/lib/mimalloc-1.2/libmimalloc.a \
 	-Wl,-whole-archive /lwan/build/src/lib/liblwan.a -Wl,-no-whole-archive \
 	`pkg-config mariadb --libs` \
 	`pkg-config sqlite3 --libs` \

+ 6 - 3
frameworks/C/lwan/lwan.dockerfile

@@ -1,4 +1,4 @@
-FROM ubuntu:19.04
+FROM ubuntu:19.10
 
 RUN apt update -yqq
 RUN apt install -yqq \
@@ -8,9 +8,12 @@ RUN apt install -yqq \
 ADD ./ /lwan
 WORKDIR /lwan
 
-RUN wget https://github.com/lpereira/lwan/archive/d7fc0d27fbea5c68d61444033517d0e962e822e6.tar.gz -O - | tar xz --strip-components=1 && \
+RUN mkdir mimalloc && \
+    wget https://github.com/microsoft/mimalloc/archive/acb03c54971c4b0a43a6d17ea55a9d5feb88972f.tar.gz -O - | tar xz --strip-components=1 -C mimalloc && \
+    cd mimalloc && mkdir build && cd build && CFLAGS="-flto -ffat-lto-objects" cmake .. -DCMAKE_BUILD_TYPE=Release -DMI_SECURE=OFF && make -j install && cd ../.. && \
+    wget https://github.com/lpereira/lwan/archive/b52c9f5e17542800a762f19bc9073bd8b3b95cb3.tar.gz -O - | tar xz --strip-components=1 && \
     mkdir build && cd build && \
-    cmake /lwan -DCMAKE_BUILD_TYPE=Release && \
+    cmake /lwan -DCMAKE_BUILD_TYPE=Release -DUSE_ALTERNATIVE_MALLOC=mimalloc && \
     make lwan-static
 
 RUN make clean && make

+ 2 - 2
frameworks/C/lwan/src/database.c

@@ -316,8 +316,8 @@ db_prepare_sqlite(const struct db *db, const char *sql, const size_t sql_len)
     if (!stmt_sqlite)
         return NULL;
 
-    int ret = sqlite3_prepare(db_sqlite->sqlite, sql, (int)sql_len,
-                              &stmt_sqlite->sqlite, NULL);
+    int ret = sqlite3_prepare_v2(db_sqlite->sqlite, sql, (int)sql_len,
+                                 &stmt_sqlite->sqlite, NULL);
     if (ret != SQLITE_OK) {
         free(stmt_sqlite);
         return NULL;

+ 9 - 4
frameworks/C/lwan/src/json.c

@@ -393,7 +393,12 @@ static int decode_num(const struct token *token, int32_t *num)
     *token->end = '\0';
 
     errno = 0;
-    *num = strtol(token->start, &endptr, 10);
+    long v = strtol(token->start, &endptr, 10);
+    if ((long)(int)v != v) {
+        return -ERANGE;
+    }
+
+    *num = (int)v;
 
     *token->end = prev_end;
 
@@ -482,7 +487,7 @@ static ptrdiff_t get_elem_size(const struct json_obj_descr *descr)
     case JSON_TOK_FALSE:
         return sizeof(bool);
     case JSON_TOK_LIST_START:
-        return descr->array.n_elements *
+        return (ptrdiff_t)descr->array.n_elements *
                get_elem_size(descr->array.element_descr);
     case JSON_TOK_OBJECT_START: {
         ptrdiff_t total = 0;
@@ -491,7 +496,7 @@ static ptrdiff_t get_elem_size(const struct json_obj_descr *descr)
         for (i = 0; i < descr->object.sub_descr_len; i++) {
             ptrdiff_t s = get_elem_size(&descr->object.sub_descr[i]);
 
-            total += ROUND_UP(s, 1 << descr->object.sub_descr[i].align_shift);
+            total += (ptrdiff_t)ROUND_UP(s, 1 << descr->object.sub_descr[i].align_shift);
         }
 
         return total;
@@ -508,7 +513,7 @@ static int arr_parse(struct json_obj *obj,
                      void *val)
 {
     ptrdiff_t elem_size = get_elem_size(elem_descr);
-    void *last_elem = (char *)field + elem_size * max_elements;
+    void *last_elem = (char *)field + elem_size * (ptrdiff_t)max_elements;
     size_t *elements = (size_t *)((char *)val + elem_descr->offset);
     struct token value;
 

+ 4 - 19
frameworks/C/lwan/src/json.h

@@ -55,26 +55,11 @@ enum json_tokens {
 struct json_obj_descr {
     const char *field_name;
 
-    /* Alignment can be 1, 2, 4, or 8.  The macros to create
-     * a struct json_obj_descr will store the alignment's
-     * power of 2 in order to keep this value in the 0-3 range
-     * and thus use only 2 bits.
-     */
-    uint32_t align_shift : 2;
-
-    /* 127 characters is more than enough for a field name. */
-    uint32_t field_name_len : 7;
-
-    /* Valid values here (enum json_tokens): JSON_TOK_STRING,
-     * JSON_TOK_NUMBER, JSON_TOK_TRUE, JSON_TOK_FALSE,
-     * JSON_TOK_OBJECT_START, JSON_TOK_LIST_START.  (All others
-     * ignored.) Maximum value is '}' (125), so this has to be 7 bits
-     * long.
-     */
-    uint32_t type : 7;
 
-    /* 65535 bytes is more than enough for many JSON payloads. */
-    uint32_t offset : 16;
+    uint32_t align_shift;
+    uint32_t field_name_len;
+    uint32_t type;
+    uint32_t offset;
 
     union {
         struct {

+ 9 - 5
frameworks/C/lwan/src/techempower.c

@@ -160,6 +160,8 @@ static enum lwan_http_status json_response(struct lwan_response *response,
                                            size_t descr_len,
                                            const void *data)
 {
+    lwan_strbuf_grow_to(response->buffer, 128);
+
     if (json_obj_encode(descr, descr_len, data, append_to_strbuf,
                         response->buffer) < 0)
         return HTTP_INTERNAL_ERROR;
@@ -242,7 +244,7 @@ LWAN_HANDLER(queries)
     if (UNLIKELY(!stmt))
         return HTTP_INTERNAL_ERROR;
 
-    struct queries_json qj = {.queries_len = queries};
+    struct queries_json qj = {.queries_len = (size_t)queries};
     struct db_row rows[1] = {{.kind = 'i'}};
     struct db_row results[] = {{.kind = 'i'}, {.kind = '\0'}};
     for (long i = 0; i < queries; i++) {
@@ -281,7 +283,7 @@ static int fortune_compare(const void *a, const void *b)
     size_t min_len = a_len < b_len ? a_len : b_len;
 
     int cmp = memcmp(fortune_a->item.message, fortune_b->item.message, min_len);
-    return cmp == 0 ? -(ssize_t)min_len : cmp;
+    return cmp == 0 ? -(int)(ssize_t)min_len : cmp;
 }
 
 static bool append_fortune(struct coro *coro,
@@ -353,6 +355,8 @@ LWAN_HANDLER(fortunes)
 {
     struct Fortune fortune;
 
+    lwan_strbuf_grow_to(response->buffer, 1500);
+
     if (UNLIKELY(!lwan_tpl_apply_with_buffer(fortune_tpl, response->buffer,
                                              &fortune)))
         return HTTP_INTERNAL_ERROR;
@@ -395,9 +399,9 @@ int main(void)
         if (!db_connection_params.mysql.database)
             lwan_status_critical("No MySQL database provided");
     } else {
-        const char *pragmas[] = {"PRAGMA mmap_size=44040192",
-                                 "PRAGMA journal_mode=OFF",
-                                 "PRAGMA locking_mode=EXCLUSIVE", NULL};
+        static const char *pragmas[] = {"PRAGMA mmap_size=44040192",
+                                        "PRAGMA journal_mode=OFF",
+                                        "PRAGMA locking_mode=EXCLUSIVE", NULL};
         db_connection_params = (struct db_connection_params) {
             .type = DB_CONN_SQLITE,
             .sqlite.path = "techempower.db",