Ori.livneh has submitted this change and it was merged.

Change subject: perf: use strtok_r + strtod / strtoull instead of scanf
......................................................................


perf: use strtok_r + strtod / strtoull instead of scanf

mwprof spends most of its time in scanf. Parsing the string by hand reduced CPU
utilization by a third.

Change-Id: Id4a3dab276ab826684c8c45589fb81955e1e0688
---
M Makefile
M collector.c
M mwprof.c
M mwprof.h
4 files changed, 64 insertions(+), 45 deletions(-)

Approvals:
  Ori.livneh: Verified; Looks good to me, approved



diff --git a/Makefile b/Makefile
index 9eebac9..586bc57 100644
--- a/Makefile
+++ b/Makefile
@@ -1,4 +1,4 @@
-CFLAGS+=-Wall -g $(shell pkg-config --cflags --libs glib-2.0 gio-2.0 
gthread-2.0 gio-unix-2.0)
+CFLAGS+=-Wall -O2 -g $(shell pkg-config --cflags --libs glib-2.0 gio-2.0 
gthread-2.0 gio-unix-2.0)
 LDLIBS+=$(shell pkg-config --libs glib-2.0 gio-2.0 gthread-2.0 gio-unix-2.0)
 
 all: mwprof
diff --git a/collector.c b/collector.c
index 5b84646..e735765 100644
--- a/collector.c
+++ b/collector.c
@@ -7,55 +7,86 @@
  * License: public domain (as if there's something to protect ;-)
  */
 #include <stdio.h>
+#include <stdlib.h>
 #include <string.h>
 #include <glib.h>
 #include "mwprof.h"
 
 /* Decides what to do with sample UDP message */
 void
-handleMessage(gchar *buffer, gssize length) {
-    gchar *p, *pp;
-    gchar host[128];
-    gchar db[128];
-    gchar task[1024];
-    gchar stats[] = "stats/";
-    gint n_fields;
-
+handleMessage(gchar *buffer) {
+    gchar *host, *db, *task;
+    gchar *line, *saveptr, *token;
     CallStats sample;
-    /* db host count cpu cpusq real realsq eventdescription */
-    const char msgformat[]="%127s %127s %ld %lf %lf %lf %lf %1023[^\n]";
-
-    buffer[length] = 0;
-    pp = buffer;
 
     while (TRUE) {
-        p = strsep(&pp, "\r\n");
+        line = strsep(&buffer, "\r\n");
 
-        if (p == NULL) {
+        if (line == NULL) {
             break;
-        } else if (p[0] == '\0') {
+        } else if (line[0] == '\0') {
             continue;
         }
 
-        if (strcmp("-truncate", p) == 0) {
+        if (g_str_has_prefix(buffer, "-truncate")) {
             truncateData();
-            return;
+            continue;
         }
 
         memset(&sample, '\0', sizeof(sample));
-        n_fields = sscanf(p, msgformat, (char *) &db, (char *) &host,
-                          &sample.count, &sample.cpu, &sample.cpu_sq,
-                          &sample.real, &sample.real_sq, (char *) &task);
 
-        if (n_fields < 7) {
+        token = strtok_r(line, " ", &saveptr);
+        if (token == NULL || strnlen(token, 128) > 127) {
+            break;
+        }
+        db = token;
+
+        token = strtok_r(NULL, " ", &saveptr);
+        if (token == NULL || strnlen(token, 128) > 127) {
             continue;
         }
+        host = token;
+
+        token = strtok_r(NULL, " ", &saveptr);
+        if (token == NULL) {
+            continue;
+        }
+        sample.count = strtoull(token, NULL, 10);
+
+        token = strtok_r(NULL, " ", &saveptr);
+        if (token == NULL) {
+            continue;
+        }
+        sample.cpu = g_ascii_strtod(token, NULL);
+
+        token = strtok_r(NULL, " ", &saveptr);
+        if (token == NULL) {
+            continue;
+        }
+        sample.cpu_sq = g_ascii_strtod(token, NULL);
+
+        token = strtok_r(NULL, " ", &saveptr);
+        if (token == NULL) {
+            continue;
+        }
+        sample.real = g_ascii_strtod(token, NULL);
+
+        token = strtok_r(NULL, " ", &saveptr);
+        if (token == NULL) {
+            continue;
+        }
+        sample.real_sq = g_ascii_strtod(token, NULL);
+
+        if (saveptr[0] == '\0' || strnlen(saveptr, 1024) > 1023) {
+            continue;
+        }
+        task = saveptr;
 
         // Update the DB-specific entry
         updateEntry(db, host, task, &sample);
 
         // Update the aggregate entry
-        if (strncmp(db, stats, sizeof(stats)-1) == 0) {
+        if (g_str_has_prefix(db, "stats/")) {
             updateEntry("stats/all", "-", task, &sample);
         } else {
             updateEntry("all", "-", task, &sample);
@@ -69,10 +100,9 @@
     CallStats *entry;
 
     snprintf(key, sizeof(key) - 1, "%s:%s:%s", db, host, task);
-
     entry = g_hash_table_lookup(table, key);
     if (entry == NULL) {
-        entry = g_malloc0(sizeof(CallStats));
+        entry = g_new0(CallStats, 1);
         g_mutex_init(&entry->mutex);
         g_mutex_lock(&entry->mutex);
         G_LOCK(table);
diff --git a/mwprof.c b/mwprof.c
index 28df8a6..05f7bef 100644
--- a/mwprof.c
+++ b/mwprof.c
@@ -46,31 +46,19 @@
     FILE *temp;
     GInputStream *in;
     GOutputStream *out;
-    GError *error = NULL;
-
 
     temp = tmpfile();
     g_assert(temp != NULL);
 
     dumpData(temp);
     rewind(temp);
-    if (errno) {
-        g_error("rewind() failed: %s", g_strerror(errno));
-    }
 
-    in = g_unix_input_stream_new(fileno(temp), TRUE);
-
+    in = g_unix_input_stream_new(fileno(temp), FALSE);
     out = g_io_stream_get_output_stream(G_IO_STREAM(connection));
-    g_output_stream_splice(out, in, G_OUTPUT_STREAM_SPLICE_CLOSE_SOURCE |
-                           G_OUTPUT_STREAM_SPLICE_CLOSE_TARGET, NULL, &error);
-    g_assert_no_error(error);
-
-    g_input_stream_close(G_INPUT_STREAM(in), NULL, &error);
-    g_assert_no_error(error);
+    g_output_stream_splice(out, in, G_OUTPUT_STREAM_SPLICE_NONE, NULL, NULL);
 
     g_object_unref(in);
-    g_output_stream_close(out, NULL, &error);
-    g_assert_no_error(error);
+    fclose(temp);
 
     return FALSE;
 }
@@ -83,7 +71,7 @@
     GInetAddress *inet_address;
     GSocketAddress *address;
     gint port = GPOINTER_TO_INT(data);
-    gchar buffer[65535] = {0};
+    gchar buf[65535] = {0};
     gssize nbytes;
 
     stats_sock = g_socket_new(G_SOCKET_FAMILY_IPV6, G_SOCKET_TYPE_DATAGRAM,
@@ -99,9 +87,10 @@
     g_object_unref(address);
 
     while (TRUE) {
-        nbytes = g_socket_receive(stats_sock, buffer, 65535, NULL, &error);
+        nbytes = g_socket_receive(stats_sock, buf, sizeof(buf)-1, NULL, 
&error);
         g_assert_no_error(error);
-        handleMessage((char *) &buffer, (ssize_t) nbytes);
+        buf[nbytes] = '\0';
+        handleMessage(buf);
     }
 }
 
diff --git a/mwprof.h b/mwprof.h
index 889935e..ad9c31f 100644
--- a/mwprof.h
+++ b/mwprof.h
@@ -30,7 +30,7 @@
 
 void dumpData(FILE *fd);
 void truncateData();
-void handleMessage(char *buffer, ssize_t length);
+void handleMessage(gchar *buffer);
 void updateEntry(char *db, char *host, char *task, CallStats *sample);
 
 #endif  // MWPROF_H_

-- 
To view, visit https://gerrit.wikimedia.org/r/104010
To unsubscribe, visit https://gerrit.wikimedia.org/r/settings

Gerrit-MessageType: merged
Gerrit-Change-Id: Id4a3dab276ab826684c8c45589fb81955e1e0688
Gerrit-PatchSet: 1
Gerrit-Project: operations/software/mwprof
Gerrit-Branch: master
Gerrit-Owner: Ori.livneh <o...@wikimedia.org>
Gerrit-Reviewer: Ori.livneh <o...@wikimedia.org>

_______________________________________________
MediaWiki-commits mailing list
MediaWiki-commits@lists.wikimedia.org
https://lists.wikimedia.org/mailman/listinfo/mediawiki-commits

Reply via email to