journalist 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 7db826c70d439a2ee0ad1e9f9f67dfd8b6209471
4
+ data.tar.gz: ce108b771e21a517521b19efec110a6a1b81a935
5
+ SHA512:
6
+ metadata.gz: f49a58bff0124333d6a4fa06b5a3dcfa888aa5d94e493de4d8544dd750d3d8590090923e707932278fb701e704b7ded55c48e4cd8e3645abc0a689bc29b46c12
7
+ data.tar.gz: 3000484d221a0bbe164902f6290cfc3bf8900f55e938f14691e2be5a67773ee139a5988ec2ccb29d3337d29049c2c4218a14dfed6554d1710e2e48c856697ca2
data/.consolerc ADDED
@@ -0,0 +1,10 @@
1
+ def start
2
+ Journalist.start
3
+ stress_gc
4
+ end
5
+
6
+ def stress_gc
7
+ 100_000.times { "foo" }
8
+ end
9
+
10
+ puts "Fixtures loaded"
data/.gitignore ADDED
@@ -0,0 +1,14 @@
1
+ /.bundle/
2
+ /.yardoc
3
+ /Gemfile.lock
4
+ /_yardoc/
5
+ /coverage/
6
+ /doc/
7
+ /pkg/
8
+ /spec/reports/
9
+ /tmp/
10
+ *.bundle
11
+ *.so
12
+ *.o
13
+ *.a
14
+ mkmf.log
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in journalist.gemspec
4
+ gemspec
data/LICENSE.txt ADDED
@@ -0,0 +1,22 @@
1
+ Copyright (c) 2014 Andre Medeiros
2
+
3
+ MIT License
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining
6
+ a copy of this software and associated documentation files (the
7
+ "Software"), to deal in the Software without restriction, including
8
+ without limitation the rights to use, copy, modify, merge, publish,
9
+ distribute, sublicense, and/or sell copies of the Software, and to
10
+ permit persons to whom the Software is furnished to do so, subject to
11
+ the following conditions:
12
+
13
+ The above copyright notice and this permission notice shall be
14
+ included in all copies or substantial portions of the Software.
15
+
16
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,47 @@
1
+ # Journalist
2
+
3
+ A gem that allows you to look into a running Ruby process.
4
+
5
+ ## Motivation
6
+
7
+ We lack the tools to have real time visibility in Ruby processes. After seeing [VisualVM](http://visualvm.java.net/) at Baruco, I've realised that a tool like that for CRuby would be amazing. Thus, Journalist was born.
8
+
9
+ ## Installation
10
+
11
+ Add this line to your application's Gemfile:
12
+
13
+ ```ruby
14
+ gem 'journalist'
15
+ ```
16
+
17
+ And then execute:
18
+
19
+ $ bundle
20
+
21
+ Or install it yourself as:
22
+
23
+ $ gem install journalist
24
+
25
+ ## Usage
26
+
27
+ To start profiling, type:
28
+
29
+ Journalist.start
30
+
31
+ There are a lot of limitations right now, such as this only working for one process at any given time.
32
+
33
+ ## TODO
34
+
35
+ - [ ] Finish call/return tracepoints
36
+ - [ ] Implement allocation tracepoints
37
+ - [ ] Implement msgpack serialization
38
+ - [ ] Implement command and stream sockets
39
+ - [ ] Build GUI
40
+
41
+ ## Contributing
42
+
43
+ 1. Fork it ( https://github.com/journalistrb/journalist/fork )
44
+ 2. Create your feature branch (`git checkout -b my-new-feature`)
45
+ 3. Commit your changes (`git commit -am 'Add some feature'`)
46
+ 4. Push to the branch (`git push origin my-new-feature`)
47
+ 5. Create a new Pull Request
data/Rakefile ADDED
@@ -0,0 +1,7 @@
1
+ require "bundler/gem_tasks"
2
+
3
+ require "rake/extensiontask"
4
+
5
+ Rake::ExtensionTask.new("journalist") do |ext|
6
+ ext.lib_dir = "lib/journalist"
7
+ end
@@ -0,0 +1,70 @@
1
+ #include "calls.h"
2
+
3
+ static struct {
4
+ VALUE c_call;
5
+ VALUE c_return;
6
+ } calls_tp_hook;
7
+
8
+ // TODO: For now, a very basic counter. What we really want to do is keep around
9
+ // the trace argument, and keep track of what's going on at all times (maybe
10
+ // even benchmark how long calls take and only output the info on return.)
11
+ static int stack_size = 0;
12
+
13
+ const char c_call_fmt[] = "c_call: "
14
+ "class %s method: %s class_method %d stack_depth %d "
15
+ "path %s line %d\n";
16
+
17
+ static void
18
+ journalist_on_call_c_call(VALUE tpval, void *data) {
19
+ rb_trace_arg_t *tparg = rb_tracearg_from_tracepoint(tpval);
20
+
21
+ VALUE self = rb_tracearg_self(tparg);
22
+ VALUE method_id = rb_tracearg_method_id(tparg);
23
+ VALUE path = rb_tracearg_path(tparg);
24
+ VALUE lineno = rb_tracearg_lineno(tparg);
25
+
26
+ bool instance = TYPE(self) == T_CLASS || TYPE(self) == T_MODULE;
27
+
28
+ char buffer[4096];
29
+ sprintf(buffer,
30
+ c_call_fmt,
31
+ rb_obj_classname(self),
32
+ rb_id2name(SYM2ID(method_id)),
33
+ instance,
34
+ stack_size,
35
+ RSTRING_PTR(path),
36
+ NUM2INT(lineno)
37
+ );
38
+
39
+ rb_journalist_socket_send(buffer);
40
+ stack_size++;
41
+ }
42
+
43
+ static void
44
+ journalist_on_call_c_return(VALUE tpval, void *data) {
45
+ if(stack_size == 0) return;
46
+
47
+ rb_journalist_socket_send("c_return\n");
48
+ stack_size--;
49
+ }
50
+
51
+ void
52
+ rb_journalist_calls_init() {
53
+ calls_tp_hook.c_call = rb_tracepoint_new(0, RUBY_EVENT_C_CALL, journalist_on_call_c_call, 0);
54
+ calls_tp_hook.c_return = rb_tracepoint_new(0, RUBY_EVENT_C_RETURN, journalist_on_call_c_return, 0);
55
+
56
+ rb_gc_register_address(&calls_tp_hook.c_call);
57
+ rb_gc_register_address(&calls_tp_hook.c_return);
58
+ }
59
+
60
+ void
61
+ rb_journalist_calls_start() {
62
+ rb_tracepoint_enable(calls_tp_hook.c_call);
63
+ rb_tracepoint_enable(calls_tp_hook.c_return);
64
+ }
65
+
66
+ void
67
+ rb_journalist_calls_stop() {
68
+ rb_tracepoint_disable(calls_tp_hook.c_call);
69
+ rb_tracepoint_disable(calls_tp_hook.c_return);
70
+ }
@@ -0,0 +1,10 @@
1
+ #ifndef CALLS_H
2
+ #define CALLS_H 1
3
+
4
+ #include "journalist.h"
5
+
6
+ void rb_journalist_calls_init();
7
+ void rb_journalist_calls_start();
8
+ void rb_journalist_calls_stop();
9
+
10
+ #endif /* CALLS_H */
@@ -0,0 +1,5 @@
1
+ require "mkmf"
2
+
3
+ $CFLAGS << " -Wall -Werror -Wno-unused-parameter "
4
+
5
+ create_makefile("journalist/journalist")
@@ -0,0 +1,139 @@
1
+ #include "garbage_collection.h"
2
+
3
+ static struct {
4
+ VALUE start;
5
+ VALUE end_mark;
6
+ VALUE end_sweep;
7
+ } gc_tp_hook;
8
+
9
+ static struct {
10
+ VALUE gc;
11
+ } cookie;
12
+
13
+ static VALUE sym_count,
14
+ sym_heap_used,
15
+ sym_heap_length,
16
+ sym_heap_increment,
17
+ sym_heap_live_slot,
18
+ sym_heap_free_slot,
19
+ sym_heap_final_slot,
20
+ sym_heap_swept_slot,
21
+ sym_total_allocated_object,
22
+ sym_total_freed_object,
23
+ sym_malloc_increase,
24
+ sym_malloc_limit,
25
+ sym_minor_gc_count,
26
+ sym_major_gc_count,
27
+ sym_remembered_shady_object,
28
+ sym_remembered_shady_object_limit,
29
+ sym_old_object,
30
+ sym_old_object_limit,
31
+ sym_oldmalloc_increase,
32
+ sym_oldmalloc_limit;
33
+
34
+ const char gc_end_sweep_fmt[] = "gc_end_sweep: "
35
+ "count %d heap_used %d heap_length %d heap_live_slot %d heap_free_slot %d "
36
+ "heap_final_slot %d heap_swept_slot %d total_allocated_object %d "
37
+ "total_freed_object %d malloc_increase %d malloc_limit %d "
38
+ "minor_gc_count %d major_gc_count %d remembered_shady_object %d "
39
+ "remembered_shady_object_limit %d old_object %d old_object_limit %d "
40
+ "oldmalloc_increase %d oldmalloc_limit %d\n";
41
+
42
+ static void
43
+ journalist_on_gc_start(VALUE tpval, void *data) {
44
+ rb_journalist_socket_send("gc_start\n");
45
+ }
46
+
47
+ static void
48
+ journalist_on_gc_end_mark(VALUE tpval, void *data) {
49
+ rb_journalist_socket_send("gc_mark\n");
50
+ }
51
+
52
+ static void
53
+ journalist_on_gc_end_sweep(VALUE tpval, void *data) {
54
+ char buffer[4096];
55
+ rb_gc_stat(cookie.gc);
56
+
57
+ #define STAT(name) NUM2INT(rb_hash_aref(cookie.gc, sym_##name))
58
+ sprintf(buffer,
59
+ gc_end_sweep_fmt,
60
+ STAT(count),
61
+ STAT(heap_used),
62
+ STAT(heap_length),
63
+ STAT(heap_live_slot),
64
+ STAT(heap_free_slot),
65
+ STAT(heap_final_slot),
66
+ STAT(heap_swept_slot),
67
+ STAT(total_allocated_object),
68
+ STAT(total_freed_object),
69
+ STAT(malloc_increase),
70
+ STAT(malloc_limit),
71
+ STAT(minor_gc_count),
72
+ STAT(major_gc_count),
73
+ STAT(remembered_shady_object),
74
+ STAT(remembered_shady_object_limit),
75
+ STAT(old_object),
76
+ STAT(old_object_limit),
77
+ STAT(oldmalloc_increase),
78
+ STAT(oldmalloc_limit)
79
+ );
80
+ #undef STAT
81
+
82
+ rb_journalist_socket_send(buffer);
83
+ }
84
+
85
+ void
86
+ rb_journalist_gc_init() {
87
+ // Initialize symbols
88
+ #define S(name) sym_##name = ID2SYM(rb_intern_const(#name));
89
+ S(count);
90
+ S(heap_used);
91
+ S(heap_length);
92
+ S(heap_increment);
93
+ S(heap_live_slot);
94
+ S(heap_free_slot);
95
+ S(heap_final_slot);
96
+ S(heap_swept_slot);
97
+ S(total_allocated_object);
98
+ S(total_freed_object);
99
+ S(malloc_increase);
100
+ S(malloc_limit);
101
+ S(minor_gc_count);
102
+ S(major_gc_count);
103
+ S(remembered_shady_object);
104
+ S(remembered_shady_object_limit);
105
+ S(old_object);
106
+ S(old_object_limit);
107
+ S(oldmalloc_increase);
108
+ S(oldmalloc_limit);
109
+ #undef S
110
+
111
+ // Grab the latest info on GC. We need to do this so that Ruby does all the
112
+ // allocations it needs for this object outside of GC, so that we don't
113
+ // blow up the interpreter. Also, mark it so that GC doesn't reap it on a run.
114
+ cookie.gc = rb_hash_new();
115
+ rb_gc_register_mark_object(cookie.gc);
116
+ rb_gc_stat(cookie.gc);
117
+
118
+ gc_tp_hook.start = rb_tracepoint_new(0, RUBY_INTERNAL_EVENT_GC_START, journalist_on_gc_start, 0);
119
+ gc_tp_hook.end_mark = rb_tracepoint_new(0, RUBY_INTERNAL_EVENT_GC_END_MARK, journalist_on_gc_end_mark, 0);
120
+ gc_tp_hook.end_sweep = rb_tracepoint_new(0, RUBY_INTERNAL_EVENT_GC_END_SWEEP, journalist_on_gc_end_sweep, 0);
121
+
122
+ rb_gc_register_address(&gc_tp_hook.start);
123
+ rb_gc_register_address(&gc_tp_hook.end_mark);
124
+ rb_gc_register_address(&gc_tp_hook.end_sweep);
125
+ }
126
+
127
+ void
128
+ rb_journalist_gc_start() {
129
+ rb_tracepoint_enable(gc_tp_hook.start);
130
+ rb_tracepoint_enable(gc_tp_hook.end_mark);
131
+ rb_tracepoint_enable(gc_tp_hook.end_sweep);
132
+ }
133
+
134
+ void
135
+ rb_journalist_gc_stop() {
136
+ rb_tracepoint_disable(gc_tp_hook.start);
137
+ rb_tracepoint_disable(gc_tp_hook.end_mark);
138
+ rb_tracepoint_disable(gc_tp_hook.end_sweep);
139
+ }
@@ -0,0 +1,10 @@
1
+ #ifndef GARBAGE_COLLECTION_H
2
+ #define GARBAGE_COLLECTION_H 1
3
+
4
+ #include "journalist.h"
5
+
6
+ void rb_journalist_gc_init();
7
+ void rb_journalist_gc_start();
8
+ void rb_journalist_gc_stop();
9
+
10
+ #endif /* GARBAGE_COLLECTION_H */
@@ -0,0 +1,38 @@
1
+ #include "journalist.h"
2
+
3
+ VALUE rb_mJournalist;
4
+
5
+ static void
6
+ rb_journalist_init() {
7
+ rb_journalist_socket_init();
8
+
9
+ rb_journalist_gc_init();
10
+ rb_journalist_calls_init();
11
+ }
12
+
13
+ static VALUE
14
+ journalist_start(VALUE klass) {
15
+ rb_journalist_gc_start();
16
+ rb_journalist_calls_start();
17
+
18
+ return Qtrue;
19
+ }
20
+
21
+ static VALUE
22
+ journalist_stop(VALUE klass) {
23
+ rb_journalist_gc_stop();
24
+ rb_journalist_calls_stop();
25
+
26
+ return Qtrue;
27
+ }
28
+
29
+ void
30
+ Init_journalist(void)
31
+ {
32
+ rb_mJournalist = rb_define_module("Journalist");
33
+
34
+ rb_define_singleton_method(rb_mJournalist, "start", journalist_start, 0);
35
+ rb_define_singleton_method(rb_mJournalist, "stop", journalist_stop, 0);
36
+
37
+ rb_journalist_init();
38
+ }
@@ -0,0 +1,13 @@
1
+ #ifndef JOURNALIST_H
2
+ #define JOURNALIST_H 1
3
+
4
+ #include <stdbool.h>
5
+
6
+ #include "ruby.h"
7
+ #include "ruby/debug.h"
8
+
9
+ #include "calls.h"
10
+ #include "garbage_collection.h"
11
+ #include "socket.h"
12
+
13
+ #endif /* JOURNALIST_H */
@@ -0,0 +1,15 @@
1
+ #include "socket.h"
2
+
3
+ FILE *journalist_file;
4
+ static char journalist_file_path[] = "/tmp/journalist";
5
+
6
+ void
7
+ rb_journalist_socket_init() {
8
+ journalist_file = fopen(journalist_file_path, "w");
9
+ }
10
+
11
+ void
12
+ rb_journalist_socket_send(char *message) {
13
+ fwrite(message, sizeof(char), strlen(message), journalist_file);
14
+ fflush(journalist_file);
15
+ }
@@ -0,0 +1,14 @@
1
+ #ifndef ASDASDASD
2
+ #define ASDASDASD 1
3
+
4
+ #include <stdio.h>
5
+ #include <sys/socket.h>
6
+ #include <sys/un.h>
7
+ #include <stdlib.h>
8
+ #include <string.h>
9
+ #include <unistd.h>
10
+
11
+ void rb_journalist_socket_init();
12
+ void rb_journalist_socket_send(char *message);
13
+
14
+ #endif /* ASDASDASD */
@@ -0,0 +1,29 @@
1
+ # coding: utf-8
2
+ lib = File.expand_path('../lib', __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require 'journalist/version'
5
+
6
+ Gem::Specification.new do |spec|
7
+ spec.name = "journalist"
8
+ spec.version = Journalist::VERSION
9
+ spec.authors = ["Andre Medeiros"]
10
+ spec.email = ["me@andremedeiros.info"]
11
+ spec.extensions = ["ext/journalist/extconf.rb"]
12
+ spec.summary = %q{Easily look into a running Ruby process.}
13
+ spec.description = <<-DESC.gsub(/^\s|\t|\n/, '').lstrip
14
+ Journalist is a gem that intends to make it really easy to get visibility
15
+ into any running Ruby processes with metrics like GC stats, performance and
16
+ allocations.
17
+ DESC
18
+ spec.homepage = "https://github.com/journalistrb/journalist"
19
+ spec.license = "MIT"
20
+
21
+ spec.files = `git ls-files -z`.split("\x0")
22
+ spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
23
+ spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
24
+ spec.require_paths = ["lib"]
25
+
26
+ spec.add_development_dependency "bundler", "~> 1.7"
27
+ spec.add_development_dependency "rake", "~> 10.0"
28
+ spec.add_development_dependency "rake-compiler"
29
+ end
data/lib/journalist.rb ADDED
@@ -0,0 +1,6 @@
1
+ require "journalist/version"
2
+ require "journalist/journalist"
3
+
4
+ module Journalist
5
+ # Your code goes here...
6
+ end
@@ -0,0 +1,3 @@
1
+ module Journalist
2
+ VERSION = "0.0.1"
3
+ end
metadata ADDED
@@ -0,0 +1,106 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: journalist
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.1
5
+ platform: ruby
6
+ authors:
7
+ - Andre Medeiros
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2014-09-18 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: bundler
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: '1.7'
20
+ type: :development
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "~>"
25
+ - !ruby/object:Gem::Version
26
+ version: '1.7'
27
+ - !ruby/object:Gem::Dependency
28
+ name: rake
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - "~>"
32
+ - !ruby/object:Gem::Version
33
+ version: '10.0'
34
+ type: :development
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - "~>"
39
+ - !ruby/object:Gem::Version
40
+ version: '10.0'
41
+ - !ruby/object:Gem::Dependency
42
+ name: rake-compiler
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - ">="
46
+ - !ruby/object:Gem::Version
47
+ version: '0'
48
+ type: :development
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - ">="
53
+ - !ruby/object:Gem::Version
54
+ version: '0'
55
+ description: Journalist is a gem that intends to make it really easy to get visibility into
56
+ any running Ruby processes with metrics like GC stats, performance and allocations.
57
+ email:
58
+ - me@andremedeiros.info
59
+ executables: []
60
+ extensions:
61
+ - ext/journalist/extconf.rb
62
+ extra_rdoc_files: []
63
+ files:
64
+ - ".consolerc"
65
+ - ".gitignore"
66
+ - Gemfile
67
+ - LICENSE.txt
68
+ - README.md
69
+ - Rakefile
70
+ - ext/journalist/calls.c
71
+ - ext/journalist/calls.h
72
+ - ext/journalist/extconf.rb
73
+ - ext/journalist/garbage_collection.c
74
+ - ext/journalist/garbage_collection.h
75
+ - ext/journalist/journalist.c
76
+ - ext/journalist/journalist.h
77
+ - ext/journalist/socket.c
78
+ - ext/journalist/socket.h
79
+ - journalist.gemspec
80
+ - lib/journalist.rb
81
+ - lib/journalist/version.rb
82
+ homepage: https://github.com/journalistrb/journalist
83
+ licenses:
84
+ - MIT
85
+ metadata: {}
86
+ post_install_message:
87
+ rdoc_options: []
88
+ require_paths:
89
+ - lib
90
+ required_ruby_version: !ruby/object:Gem::Requirement
91
+ requirements:
92
+ - - ">="
93
+ - !ruby/object:Gem::Version
94
+ version: '0'
95
+ required_rubygems_version: !ruby/object:Gem::Requirement
96
+ requirements:
97
+ - - ">="
98
+ - !ruby/object:Gem::Version
99
+ version: '0'
100
+ requirements: []
101
+ rubyforge_project:
102
+ rubygems_version: 2.2.2
103
+ signing_key:
104
+ specification_version: 4
105
+ summary: Easily look into a running Ruby process.
106
+ test_files: []