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 <[email protected]>
Gerrit-Reviewer: Ori.livneh <[email protected]>
_______________________________________________
MediaWiki-commits mailing list
[email protected]
https://lists.wikimedia.org/mailman/listinfo/mediawiki-commits