Permalink
Browse files

first pass at memcached tracer

  • Loading branch information...
1 parent e25e2ad commit c71bc53760c00b6c1f51ef1ec485969e7f880674 @tmm1 tmm1 committed Apr 24, 2010
Showing with 149 additions and 1 deletion.
  1. +1 −0 ext/memprof.c
  2. +1 −0 ext/tracer.h
  3. +106 −0 ext/tracers/memcache.c
  4. +41 −1 spec/tracing_spec.rb
View
@@ -1901,6 +1901,7 @@ Init_memprof()
install_objects_tracer();
install_fd_tracer();
install_mysql_tracer();
+ install_memcache_tracer();
gc_hook = Data_Wrap_Struct(rb_cObject, sourcefile_marker, NULL, NULL);
rb_global_variable(&gc_hook);
View
@@ -45,4 +45,5 @@ extern void install_gc_tracer();
extern void install_fd_tracer();
extern void install_mysql_tracer();
extern void install_objects_tracer();
+extern void install_memcache_tracer();
#endif
View
@@ -0,0 +1,106 @@
+#include <assert.h>
+#include <errno.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/time.h>
+
+#include "arch.h"
+#include "bin_api.h"
+#include "json.h"
+#include "tracer.h"
+#include "tramp.h"
+#include "util.h"
+
+struct memprof_memcache_stats {
+ size_t get_calls;
+ size_t get_responses[45];
+};
+
+static struct tracer tracer;
+static struct memprof_memcache_stats stats;
+static const char* (*_memcached_lib_version)(void);
+static char* (*_memcached_get)(void *ptr, const char *key, size_t key_length, size_t *value_length, uint32_t *flags, void *error);
+
+static char*
+memcached_get_tramp(void *ptr, const char *key, size_t key_length, size_t *value_length, uint32_t *flags, void *error)
+{
+ char* ret = _memcached_get(ptr, key, key_length, value_length, flags, error);
+ stats.get_calls++;
+ int err = *(int*)error;
+ stats.get_responses[err > 42 ? 44 : err]++;
+ return ret;
+}
+
+static void
+memcache_trace_start() {
+ static int inserted = 0;
+
+ if (!inserted)
+ inserted = 1;
+ else
+ return;
+
+ _memcached_lib_version = bin_find_symbol("memcached_lib_version", NULL, 1);
+ if (_memcached_lib_version) {
+ const char *version = _memcached_lib_version();
+ if (strcmp(version, "0.32") == 0) {
+ _memcached_get = bin_find_symbol("memcached_get", NULL, 1);
+ insert_tramp("memcached_get", memcached_get_tramp);
+ }
+ }
+}
+
+static void
+memcache_trace_stop() {
+}
+
+static void
+memcache_trace_reset() {
+ memset(&stats, 0, sizeof(stats));
+}
+
+static void
+memcache_trace_dump(yajl_gen gen) {
+ int i;
+
+ if (stats.get_calls > 0) {
+ yajl_gen_cstr(gen, "get");
+
+ yajl_gen_map_open(gen);
+ yajl_gen_cstr(gen, "calls");
+ yajl_gen_integer(gen, stats.get_calls);
+
+ yajl_gen_cstr(gen, "responses");
+ yajl_gen_map_open(gen);
+ for (i=0; i < 45; i++) {
+ if (stats.get_responses[i]) {
+ switch (i) {
+ case 0:
+ yajl_gen_cstr(gen, "success");
+ break;
+ case 16:
+ yajl_gen_cstr(gen, "notfound");
+ break;
+ default:
+ yajl_gen_format(gen, "%d", i);
+ }
+ yajl_gen_integer(gen, stats.get_responses[i]);
+ }
+ }
+ yajl_gen_map_close(gen);
+
+ yajl_gen_map_close(gen);
+ }
+}
+
+void install_memcache_tracer()
+{
+ tracer.start = memcache_trace_start;
+ tracer.stop = memcache_trace_stop;
+ tracer.reset = memcache_trace_reset;
+ tracer.dump = memcache_trace_dump;
+ tracer.id = "memcache";
+
+ trace_insert(&tracer);
+}
View
@@ -6,6 +6,12 @@
require 'tempfile'
+# XXX must require upfront before tracers are installed
+require 'socket'
+require 'open-uri'
+require 'mysql' rescue nil
+require 'memcached' rescue nil
+
describe 'Memprof tracers' do
@tempfile = Tempfile.new('tracing_spec')
@@ -18,7 +24,6 @@ def filedata
end
should 'trace i/o for block of code' do
- require 'open-uri'
Memprof.trace(filename) do
open("http://google.com").read
end
@@ -52,6 +57,41 @@ def filedata
filedata.should =~ /"malloc":\{"calls":10/
filedata.should =~ /"realloc":\{"calls":10/
end
+
+ if defined? Mysql
+ begin
+ conn = Mysql.connect
+
+ should 'trace mysql calls for block' do
+ Memprof.trace(filename) do
+ 5.times{ conn.query("select sleep(0.05)") }
+ end
+
+ filedata.should =~ /"mysql":\{"queries":5,"time":0.2[567]/
+ end
+ rescue Mysql::Error => e
+ raise unless e.message =~ /connect/
+ end
+ end
+
+ if defined? Memcached
+ begin
+ conn = Memcached.new("localhost:11211", :show_backtraces => true)
+ conn.stats
+
+ should 'trace memcached calls for block' do
+ Memprof.trace(filename) do
+ conn.delete("memprof") rescue nil
+ conn.get("memprof") rescue nil
+ conn.set("memprof", "is cool")
+ conn.get("memprof")
+ end
+
+ filedata.should =~ /"memcache":\{"get":\{"calls":2,"responses":\{"success":1,"notfound":1/
+ end
+ rescue Memcached::SomeErrorsWereReported
+ end
+ end
end
describe 'Memprof request tracing' do

0 comments on commit c71bc53

Please sign in to comment.