fiber-profiler 0.1.3 → 0.1.4

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: a2bbdd5d629b193bb2c9fe87a9935abda45b21339bc9fa8e9a177a3cb08c6ca4
4
- data.tar.gz: c38ff2d79d1dcc2cef0745923da73c0e1bfda612623d1592fffbeb708d6ff97f
3
+ metadata.gz: 90d32f14c57f33c6c247a942a45a2cc56e3cfd673a67c32cfacdf780b21b3473
4
+ data.tar.gz: 7b666f890ca18c55d5baba91961bae7033d25fa052fc8b618eac13e28992199d
5
5
  SHA512:
6
- metadata.gz: a23c926af43a1db2f2cf71b269bbb63d0bff602ca17b40ced3da152dd317d084c2f41f47c42ba7194a7be67df6be8d17de54a829808a82173bb3dc83303b14bd
7
- data.tar.gz: afd379c5f799fda50fa7229f4512ff01297e9f7f66a32d0eaab575a77c3b66d9b7cc1d13627609193983173b725b8851bf9240ab8096881bc764b66ba83b9a73
6
+ metadata.gz: f3a93685cad55774675df4db103cc3f2308cbe342a198eadd6ac83e216e409224faf65736b648f3849b1e3faa28b0ae9298faa6b4fb75e1ddcb5c05f6c86efef
7
+ data.tar.gz: 621ee83b498452ce5d3eab1501a115b6f086f62b04800b09829e9a85143bcbd8141ea6050ff34f3afe0c52a996ec6ce62893f9e4e998b63485522409a684415e
checksums.yaml.gz.sig CHANGED
Binary file
Binary file
@@ -0,0 +1,20 @@
1
+ <?xml version="1.0" encoding="UTF-8"?>
2
+ <!DOCTYPE plist PUBLIC "-//Apple Computer//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
3
+ <plist version="1.0">
4
+ <dict>
5
+ <key>CFBundleDevelopmentRegion</key>
6
+ <string>English</string>
7
+ <key>CFBundleIdentifier</key>
8
+ <string>com.apple.xcode.dsym.Fiber_Profiler.bundle</string>
9
+ <key>CFBundleInfoDictionaryVersion</key>
10
+ <string>6.0</string>
11
+ <key>CFBundlePackageType</key>
12
+ <string>dSYM</string>
13
+ <key>CFBundleSignature</key>
14
+ <string>????</string>
15
+ <key>CFBundleShortVersionString</key>
16
+ <string>1.0</string>
17
+ <key>CFBundleVersion</key>
18
+ <string>1</string>
19
+ </dict>
20
+ </plist>
@@ -0,0 +1,5 @@
1
+ ---
2
+ triple: 'arm64-apple-darwin'
3
+ binary-path: Fiber_Profiler.bundle
4
+ relocations: []
5
+ ...
data/ext/Makefile ADDED
@@ -0,0 +1,273 @@
1
+
2
+ SHELL = /bin/sh
3
+
4
+ # V=0 quiet, V=1 verbose. other values don't work.
5
+ V = 0
6
+ V0 = $(V:0=)
7
+ Q1 = $(V:1=)
8
+ Q = $(Q1:0=@)
9
+ ECHO1 = $(V:1=@ :)
10
+ ECHO = $(ECHO1:0=@ echo)
11
+ NULLCMD = :
12
+
13
+ #### Start of system configuration section. ####
14
+
15
+ srcdir = .
16
+ topdir = /Users/samuel/.rubies/ruby-3.4.1/include/ruby-3.4.0
17
+ hdrdir = $(topdir)
18
+ arch_hdrdir = /Users/samuel/.rubies/ruby-3.4.1/include/ruby-3.4.0/arm64-darwin24
19
+ PATH_SEPARATOR = :
20
+ VPATH = $(srcdir):$(arch_hdrdir)/ruby:$(hdrdir)/ruby:$(srcdir)/fiber/profiler
21
+ prefix = $(DESTDIR)/Users/samuel/.rubies/ruby-3.4.1
22
+ rubysitearchprefix = $(rubylibprefix)/$(sitearch)
23
+ rubyarchprefix = $(rubylibprefix)/$(arch)
24
+ rubylibprefix = $(libdir)/$(RUBY_BASE_NAME)
25
+ exec_prefix = $(prefix)
26
+ vendorarchhdrdir = $(vendorhdrdir)/$(sitearch)
27
+ sitearchhdrdir = $(sitehdrdir)/$(sitearch)
28
+ rubyarchhdrdir = $(rubyhdrdir)/$(arch)
29
+ vendorhdrdir = $(rubyhdrdir)/vendor_ruby
30
+ sitehdrdir = $(rubyhdrdir)/site_ruby
31
+ rubyhdrdir = $(includedir)/$(RUBY_VERSION_NAME)
32
+ vendorarchdir = $(vendorlibdir)/$(sitearch)
33
+ vendorlibdir = $(vendordir)/$(ruby_version)
34
+ vendordir = $(rubylibprefix)/vendor_ruby
35
+ sitearchdir = $(sitelibdir)/$(sitearch)
36
+ sitelibdir = $(sitedir)/$(ruby_version)
37
+ sitedir = $(rubylibprefix)/site_ruby
38
+ rubyarchdir = $(rubylibdir)/$(arch)
39
+ rubylibdir = $(rubylibprefix)/$(ruby_version)
40
+ sitearchincludedir = $(includedir)/$(sitearch)
41
+ archincludedir = $(includedir)/$(arch)
42
+ sitearchlibdir = $(libdir)/$(sitearch)
43
+ archlibdir = $(libdir)/$(arch)
44
+ ridir = $(datarootdir)/$(RI_BASE_NAME)
45
+ modular_gc_dir = $(DESTDIR)
46
+ mandir = $(datarootdir)/man
47
+ localedir = $(datarootdir)/locale
48
+ libdir = $(exec_prefix)/lib
49
+ psdir = $(docdir)
50
+ pdfdir = $(docdir)
51
+ dvidir = $(docdir)
52
+ htmldir = $(docdir)
53
+ infodir = $(datarootdir)/info
54
+ docdir = $(datarootdir)/doc/$(PACKAGE)
55
+ oldincludedir = $(DESTDIR)/usr/include
56
+ includedir = $(SDKROOT)$(prefix)/include
57
+ runstatedir = $(localstatedir)/run
58
+ localstatedir = $(prefix)/var
59
+ sharedstatedir = $(prefix)/com
60
+ sysconfdir = $(prefix)/etc
61
+ datadir = $(datarootdir)
62
+ datarootdir = $(prefix)/share
63
+ libexecdir = $(exec_prefix)/libexec
64
+ sbindir = $(exec_prefix)/sbin
65
+ bindir = $(exec_prefix)/bin
66
+ archdir = $(rubyarchdir)
67
+
68
+
69
+ CC_WRAPPER =
70
+ CC = clang
71
+ CXX = clang++ -std=gnu++11
72
+ LIBRUBY = $(LIBRUBY_A)
73
+ LIBRUBY_A = lib$(RUBY_SO_NAME)-static.a
74
+ LIBRUBYARG_SHARED =
75
+ LIBRUBYARG_STATIC = -l$(RUBY_SO_NAME)-static -framework CoreFoundation $(MAINLIBS)
76
+ empty =
77
+ OUTFLAG = -o $(empty)
78
+ COUTFLAG = -o $(empty)
79
+ CSRCFLAG = $(empty)
80
+
81
+ RUBY_EXTCONF_H = extconf.h
82
+ cflags = $(hardenflags) -fdeclspec $(optflags) $(debugflags) $(warnflags)
83
+ cxxflags =
84
+ optflags = -O3 -fno-fast-math
85
+ debugflags = -ggdb3
86
+ warnflags = -Wall -Wextra -Wextra-tokens -Wdeprecated-declarations -Wdivision-by-zero -Wdiv-by-zero -Wimplicit-function-declaration -Wimplicit-int -Wpointer-arith -Wshorten-64-to-32 -Wwrite-strings -Wold-style-definition -Wmissing-noreturn -Wno-cast-function-type -Wno-constant-logical-operand -Wno-long-long -Wno-missing-field-initializers -Wno-overlength-strings -Wno-parentheses-equality -Wno-self-assign -Wno-tautological-compare -Wno-unused-parameter -Wno-unused-value -Wunused-variable -Wmisleading-indentation -Wundef
87
+ cppflags =
88
+ CCDLFLAGS = -fno-common
89
+ CFLAGS = $(CCDLFLAGS) $(cflags) -pipe -Wall -Wno-unknown-pragmas -std=c99 $(ARCH_FLAG)
90
+ INCFLAGS = -I. -I$(arch_hdrdir) -I$(hdrdir)/ruby/backward -I$(hdrdir) -I$(srcdir)
91
+ DEFS =
92
+ CPPFLAGS = -DRUBY_EXTCONF_H=\"$(RUBY_EXTCONF_H)\" -I/opt/local/include -D_XOPEN_SOURCE -D_DARWIN_C_SOURCE -D_DARWIN_UNLIMITED_SELECT -D_REENTRANT $(DEFS) $(cppflags)
93
+ CXXFLAGS = $(CCDLFLAGS) -fdeclspec $(ARCH_FLAG)
94
+ ldflags = -L. -fstack-protector-strong -L/opt/local/lib
95
+ dldflags = -L/opt/local/lib -Wl,-undefined,dynamic_lookup -bundle_loader '$(BUILTRUBY)'
96
+ ARCH_FLAG = -arch arm64
97
+ DLDFLAGS = $(ldflags) $(dldflags) $(ARCH_FLAG)
98
+ LDSHARED = $(CC) -dynamic -bundle
99
+ LDSHAREDXX = $(CXX) -dynamic -bundle
100
+ POSTLINK = dsymutil $@ 2>/dev/null; { test -z '$(RUBY_CODESIGN)' || codesign -s '$(RUBY_CODESIGN)' $@; }
101
+ AR = ar
102
+ LD = ld
103
+ EXEEXT =
104
+
105
+ RUBY_INSTALL_NAME = $(RUBY_BASE_NAME)
106
+ RUBY_SO_NAME = ruby.3.4
107
+ RUBYW_INSTALL_NAME =
108
+ RUBY_VERSION_NAME = $(RUBY_BASE_NAME)-$(ruby_version)
109
+ RUBYW_BASE_NAME = rubyw
110
+ RUBY_BASE_NAME = ruby
111
+
112
+ arch = arm64-darwin24
113
+ sitearch = $(arch)
114
+ ruby_version = 3.4.0
115
+ ruby = $(bindir)/$(RUBY_BASE_NAME)
116
+ RUBY = $(ruby)
117
+ BUILTRUBY = $(bindir)/$(RUBY_BASE_NAME)
118
+ ruby_headers = $(hdrdir)/ruby.h $(hdrdir)/ruby/backward.h $(hdrdir)/ruby/ruby.h $(hdrdir)/ruby/defines.h $(hdrdir)/ruby/missing.h $(hdrdir)/ruby/intern.h $(hdrdir)/ruby/st.h $(hdrdir)/ruby/subst.h $(arch_hdrdir)/ruby/config.h $(RUBY_EXTCONF_H)
119
+
120
+ RM = rm -f
121
+ RM_RF = rm -fr
122
+ RMDIRS = rmdir -p
123
+ MAKEDIRS = /opt/local/bin/gmkdir -p
124
+ INSTALL = /opt/local/bin/ginstall -c
125
+ INSTALL_PROG = $(INSTALL) -m 0755
126
+ INSTALL_DATA = $(INSTALL) -m 644
127
+ COPY = cp
128
+ TOUCH = exit >
129
+
130
+ #### End of system configuration section. ####
131
+
132
+ preload =
133
+ libpath = . $(libdir) /opt/local/lib
134
+ LIBPATH = -L. -L$(libdir) -L/opt/local/lib
135
+ DEFFILE =
136
+
137
+ CLEANFILES = mkmf.log
138
+ DISTCLEANFILES =
139
+ DISTCLEANDIRS =
140
+
141
+ extout =
142
+ extout_prefix =
143
+ target_prefix =
144
+ LOCAL_LIBS =
145
+ LIBS = -lpthread
146
+ ORIG_SRCS =
147
+ SRCS = $(ORIG_SRCS) profiler.c time.c fiber.c capture.c
148
+ OBJS = profiler.o time.o fiber.o capture.o
149
+ HDRS = $(srcdir)/extconf.h
150
+ LOCAL_HDRS =
151
+ TARGET = Fiber_Profiler
152
+ TARGET_NAME = Fiber_Profiler
153
+ TARGET_ENTRY = Init_$(TARGET_NAME)
154
+ DLLIB = $(TARGET).bundle
155
+ EXTSTATIC =
156
+ STATIC_LIB =
157
+
158
+ TIMESTAMP_DIR = .
159
+ BINDIR = $(bindir)
160
+ RUBYCOMMONDIR = $(sitedir)$(target_prefix)
161
+ RUBYLIBDIR = $(sitelibdir)$(target_prefix)
162
+ RUBYARCHDIR = $(sitearchdir)$(target_prefix)
163
+ HDRDIR = $(sitehdrdir)$(target_prefix)
164
+ ARCHHDRDIR = $(sitearchhdrdir)$(target_prefix)
165
+ TARGET_SO_DIR =
166
+ TARGET_SO = $(TARGET_SO_DIR)$(DLLIB)
167
+ CLEANLIBS = $(TARGET_SO) $(TARGET_SO:=.dSYM)
168
+ CLEANOBJS = $(OBJS) *.bak
169
+ TARGET_SO_DIR_TIMESTAMP = $(TIMESTAMP_DIR)/.sitearchdir.time
170
+
171
+ all: $(DLLIB)
172
+ static: $(STATIC_LIB)
173
+ .PHONY: all install static install-so install-rb
174
+ .PHONY: clean clean-so clean-static clean-rb
175
+
176
+ clean-static::
177
+ clean-rb-default::
178
+ clean-rb::
179
+ clean-so::
180
+ clean: clean-so clean-static clean-rb-default clean-rb
181
+ -$(Q)$(RM_RF) $(CLEANLIBS) $(CLEANOBJS) $(CLEANFILES) .*.time
182
+
183
+ distclean-rb-default::
184
+ distclean-rb::
185
+ distclean-so::
186
+ distclean-static::
187
+ distclean: clean distclean-so distclean-static distclean-rb-default distclean-rb
188
+ -$(Q)$(RM) Makefile $(RUBY_EXTCONF_H) conftest.* mkmf.log
189
+ -$(Q)$(RM) core ruby$(EXEEXT) *~ $(DISTCLEANFILES)
190
+ -$(Q)$(RMDIRS) $(DISTCLEANDIRS) 2> /dev/null || true
191
+
192
+ realclean: distclean
193
+ install: install-so install-rb
194
+
195
+ install-so: $(DLLIB) $(TARGET_SO_DIR_TIMESTAMP)
196
+ $(INSTALL_PROG) $(DLLIB) $(RUBYARCHDIR)
197
+ clean-static::
198
+ -$(Q)$(RM) $(STATIC_LIB)
199
+ install-rb: pre-install-rb do-install-rb install-rb-default
200
+ install-rb-default: pre-install-rb-default do-install-rb-default
201
+ pre-install-rb: Makefile
202
+ pre-install-rb-default: Makefile
203
+ do-install-rb:
204
+ do-install-rb-default:
205
+ pre-install-rb-default:
206
+ @$(NULLCMD)
207
+ $(TARGET_SO_DIR_TIMESTAMP):
208
+ $(Q) $(MAKEDIRS) $(@D) $(RUBYARCHDIR)
209
+ $(Q) $(TOUCH) $@
210
+
211
+ site-install: site-install-so site-install-rb
212
+ site-install-so: install-so
213
+ site-install-rb: install-rb
214
+
215
+ .SUFFIXES: .c .m .cc .mm .cxx .cpp .o .S
216
+
217
+ .cc.o:
218
+ $(ECHO) compiling $(<)
219
+ $(Q) $(CXX) $(INCFLAGS) $(CPPFLAGS) $(CXXFLAGS) $(COUTFLAG)$@ -c $(CSRCFLAG)$<
220
+
221
+ .cc.S:
222
+ $(ECHO) translating $(<)
223
+ $(Q) $(CXX) $(INCFLAGS) $(CPPFLAGS) $(CXXFLAGS) $(COUTFLAG)$@ -S $(CSRCFLAG)$<
224
+
225
+ .mm.o:
226
+ $(ECHO) compiling $(<)
227
+ $(Q) $(CXX) $(INCFLAGS) $(CPPFLAGS) $(CXXFLAGS) $(COUTFLAG)$@ -c $(CSRCFLAG)$<
228
+
229
+ .mm.S:
230
+ $(ECHO) translating $(<)
231
+ $(Q) $(CXX) $(INCFLAGS) $(CPPFLAGS) $(CXXFLAGS) $(COUTFLAG)$@ -S $(CSRCFLAG)$<
232
+
233
+ .cxx.o:
234
+ $(ECHO) compiling $(<)
235
+ $(Q) $(CXX) $(INCFLAGS) $(CPPFLAGS) $(CXXFLAGS) $(COUTFLAG)$@ -c $(CSRCFLAG)$<
236
+
237
+ .cxx.S:
238
+ $(ECHO) translating $(<)
239
+ $(Q) $(CXX) $(INCFLAGS) $(CPPFLAGS) $(CXXFLAGS) $(COUTFLAG)$@ -S $(CSRCFLAG)$<
240
+
241
+ .cpp.o:
242
+ $(ECHO) compiling $(<)
243
+ $(Q) $(CXX) $(INCFLAGS) $(CPPFLAGS) $(CXXFLAGS) $(COUTFLAG)$@ -c $(CSRCFLAG)$<
244
+
245
+ .cpp.S:
246
+ $(ECHO) translating $(<)
247
+ $(Q) $(CXX) $(INCFLAGS) $(CPPFLAGS) $(CXXFLAGS) $(COUTFLAG)$@ -S $(CSRCFLAG)$<
248
+
249
+ .c.o:
250
+ $(ECHO) compiling $(<)
251
+ $(Q) $(CC) $(INCFLAGS) $(CPPFLAGS) $(CFLAGS) $(COUTFLAG)$@ -c $(CSRCFLAG)$<
252
+
253
+ .c.S:
254
+ $(ECHO) translating $(<)
255
+ $(Q) $(CC) $(INCFLAGS) $(CPPFLAGS) $(CFLAGS) $(COUTFLAG)$@ -S $(CSRCFLAG)$<
256
+
257
+ .m.o:
258
+ $(ECHO) compiling $(<)
259
+ $(Q) $(CC) $(INCFLAGS) $(CPPFLAGS) $(CFLAGS) $(COUTFLAG)$@ -c $(CSRCFLAG)$<
260
+
261
+ .m.S:
262
+ $(ECHO) translating $(<)
263
+ $(Q) $(CC) $(INCFLAGS) $(CPPFLAGS) $(CFLAGS) $(COUTFLAG)$@ -S $(CSRCFLAG)$<
264
+
265
+ $(TARGET_SO): $(OBJS) Makefile
266
+ $(ECHO) linking shared-object $(DLLIB)
267
+ -$(Q)$(RM) $(@)
268
+ $(Q) $(LDSHARED) -o $@ $(OBJS) $(LIBPATH) $(DLDFLAGS) $(LOCAL_LIBS) $(LIBS)
269
+ $(Q) $(POSTLINK)
270
+
271
+
272
+
273
+ $(OBJS): $(HDRS) $(ruby_headers)
data/ext/capture.o ADDED
Binary file
data/ext/extconf.h ADDED
@@ -0,0 +1,5 @@
1
+ #ifndef EXTCONF_H
2
+ #define EXTCONF_H
3
+ #define HAVE_RB_FIBER_CURRENT 1
4
+ #define HAVE_RB_EXT_RACTOR_SAFE 1
5
+ #endif
@@ -14,6 +14,7 @@
14
14
 
15
15
  enum {
16
16
  DEBUG_SKIPPED = 0,
17
+ DEBUG_FILTERED = 0,
17
18
  };
18
19
 
19
20
  int Fiber_Profiler_capture_p = 0;
@@ -25,9 +26,11 @@ VALUE Fiber_Profiler_Capture = Qnil;
25
26
 
26
27
  struct Fiber_Profiler_Capture_Call {
27
28
  struct timespec enter_time;
28
- struct timespec exit_time;
29
+ double duration;
29
30
 
30
- size_t nesting;
31
+ int nesting;
32
+ size_t children;
33
+ size_t filtered;
31
34
 
32
35
  rb_event_flag_t event_flag;
33
36
  ID id;
@@ -65,43 +68,61 @@ struct Fiber_Profiler_Capture;
65
68
  typedef void(*Fiber_Profiler_Stream_Print)(struct Fiber_Profiler_Capture*, FILE* restrict);
66
69
 
67
70
  struct Fiber_Profiler_Capture {
68
- // Configuration:
71
+ // The threshold in seconds, which determines when a fiber is considered to have stalled the event loop.
69
72
  double stall_threshold;
73
+
74
+ // Whether or not to track calls.
70
75
  int track_calls;
76
+
77
+ // The sample rate of the profiler, as a fraction of 1.0, which controls how often the profiler will sample between fiber context switches.
71
78
  double sample_rate;
72
79
 
73
- // Calls that are shorter than this filter threshold will be ignored:
80
+ // Calls that are shorter than this filter threshold will be ignored.
74
81
  double filter_threshold;
75
82
 
76
- // Output handling:
83
+ // The output object to write to.
77
84
  VALUE output;
85
+
86
+ // The stream print function to use.
78
87
  Fiber_Profiler_Stream_Print print;
88
+
89
+ // The stream buffer used for printing.
79
90
  struct Fiber_Profiler_Stream stream;
80
91
 
81
- // Whether or not the profiler is currently running:
92
+ // Whether or not the profiler is currently running.
82
93
  int running;
94
+
95
+ // The thread being profiled.
83
96
  VALUE thread;
84
97
 
85
- // Whether or not to capture call data:
98
+ // Whether or not to capture call data.
86
99
  int capture;
87
100
 
101
+ // The number of stalls encountered.
88
102
  size_t stalls;
89
103
 
90
- // From this point on, the state of any profile in progress:
104
+ // The start time of the profile.
91
105
  struct timespec start_time;
106
+
107
+ // The stop time of the profile.
92
108
  struct timespec stop_time;
93
109
 
94
- // The depth of the call stack:
95
- size_t nesting;
110
+ // The depth of the call stack (can be negative).
111
+ int nesting;
112
+
113
+ // The minimum nesting level encountered during the profiling session.
114
+ int nesting_minimum;
96
115
 
97
- // The current call frame:
116
+ // The current call frame.
98
117
  struct Fiber_Profiler_Capture_Call *current;
99
118
 
119
+ // The call recorded during the profiling session.
100
120
  struct Fiber_Profiler_Deque calls;
101
121
  };
102
122
 
103
123
  void Fiber_Profiler_Capture_reset(struct Fiber_Profiler_Capture *profiler) {
104
124
  profiler->nesting = 0;
125
+ profiler->nesting_minimum = 0;
105
126
  profiler->current = NULL;
106
127
  Fiber_Profiler_Deque_truncate(&profiler->calls);
107
128
  }
@@ -111,10 +132,11 @@ void Fiber_Profiler_Capture_Call_initialize(void *element) {
111
132
 
112
133
  call->enter_time.tv_sec = 0;
113
134
  call->enter_time.tv_nsec = 0;
114
- call->exit_time.tv_sec = 0;
115
- call->exit_time.tv_nsec = 0;
135
+ call->duration = 0;
116
136
 
117
137
  call->nesting = 0;
138
+ call->children = 0;
139
+ call->filtered = 0;
118
140
 
119
141
  call->event_flag = 0;
120
142
  call->id = 0;
@@ -224,18 +246,21 @@ VALUE Fiber_Profiler_Capture_allocate(VALUE klass) {
224
246
  profiler->capture = 0;
225
247
  profiler->stalls = 0;
226
248
  profiler->nesting = 0;
249
+ profiler->nesting_minimum = 0;
227
250
  profiler->current = NULL;
228
251
 
229
252
  profiler->stall_threshold = Fiber_Profiler_Capture_stall_threshold;
230
253
  profiler->track_calls = Fiber_Profiler_Capture_track_calls;
231
254
  profiler->sample_rate = Fiber_Profiler_Capture_sample_rate;
232
255
 
233
- // Filter calls that are less than 1% of the stall threshold:
234
- profiler->filter_threshold = profiler->stall_threshold * 0.01;
256
+ // Filter calls that are less than 10% of the stall threshold:
257
+ profiler->filter_threshold = profiler->stall_threshold * 0.1;
235
258
 
236
259
  profiler->calls.element_initialize = (void (*)(void*))Fiber_Profiler_Capture_Call_initialize;
237
260
  profiler->calls.element_free = (void (*)(void*))Fiber_Profiler_Capture_Call_free;
261
+
238
262
  Fiber_Profiler_Deque_initialize(&profiler->calls, sizeof(struct Fiber_Profiler_Capture_Call));
263
+ Fiber_Profiler_Deque_reserve_default(&profiler->calls);
239
264
 
240
265
  return TypedData_Wrap_Struct(klass, &Fiber_Profiler_Capture_Type, profiler);
241
266
  }
@@ -302,20 +327,24 @@ const char *event_flag_name(rb_event_flag_t event_flag) {
302
327
  case RUBY_INTERNAL_EVENT_GC_START: return "gc-start";
303
328
  case RUBY_INTERNAL_EVENT_GC_END_MARK: return "gc-end-mark";
304
329
  case RUBY_INTERNAL_EVENT_GC_END_SWEEP: return "gc-end-sweep";
330
+ case RUBY_EVENT_LINE: return "line";
305
331
  default: return "unknown";
306
332
  }
307
333
  }
308
334
 
309
- static struct Fiber_Profiler_Capture_Call* profiler_event_record_call(struct Fiber_Profiler_Capture *profiler, rb_event_flag_t event_flag, ID id, VALUE klass) {
335
+ static struct Fiber_Profiler_Capture_Call* Fiber_Profiler_Capture_Call_new(struct Fiber_Profiler_Capture *profiler, rb_event_flag_t event_flag, ID id, VALUE klass) {
310
336
  struct Fiber_Profiler_Capture_Call *call = Fiber_Profiler_Deque_push(&profiler->calls);
311
337
 
312
338
  call->event_flag = event_flag;
313
339
 
314
340
  call->parent = profiler->current;
341
+ if (call->parent) {
342
+ call->parent->children += 1;
343
+ }
344
+
315
345
  profiler->current = call;
316
-
346
+
317
347
  call->nesting = profiler->nesting;
318
- profiler->nesting += 1;
319
348
 
320
349
  if (id) {
321
350
  call->id = id;
@@ -333,6 +362,43 @@ static struct Fiber_Profiler_Capture_Call* profiler_event_record_call(struct Fib
333
362
  return call;
334
363
  }
335
364
 
365
+ // Finish the call by calculating the duration and filtering it if necessary.
366
+ int Fiber_Profiler_Capture_Call_finish(struct Fiber_Profiler_Capture *profiler, struct Fiber_Profiler_Capture_Call *call) {
367
+ // Don't filter calls if we're not running:
368
+ if (DEBUG_FILTERED) return 0;
369
+
370
+ if (call->duration < profiler->filter_threshold) {
371
+ // We can only remove calls from the end of the deque, otherwise they might be referenced by other calls:
372
+ if (call == Fiber_Profiler_Deque_last(&profiler->calls)) {
373
+ if (profiler->current == call) {
374
+ profiler->current = call->parent;
375
+ }
376
+
377
+ if (call->parent) {
378
+ call->parent->children -= 1;
379
+ call->parent->filtered += 1;
380
+ call->parent = NULL;
381
+ }
382
+
383
+ Fiber_Profiler_Deque_pop(&profiler->calls);
384
+
385
+ return 1;
386
+ }
387
+ }
388
+
389
+ return 0;
390
+ }
391
+
392
+ static const double Fiber_Profiler_Capture_Call_EXPENSIVE_THRESHOLD = 0.2;
393
+
394
+ int Fiber_Profiler_Capture_Call_expensive_p(struct Fiber_Profiler_Capture_Call *call, double total_duration) {
395
+ if (call->duration > total_duration * Fiber_Profiler_Capture_Call_EXPENSIVE_THRESHOLD) {
396
+ return 1;
397
+ }
398
+
399
+ return 0;
400
+ }
401
+
336
402
  static void Fiber_Profiler_Capture_callback(rb_event_flag_t event_flag, VALUE data, VALUE self, ID id, VALUE klass) {
337
403
  struct Fiber_Profiler_Capture *profiler = Fiber_Profiler_Capture_get(data);
338
404
 
@@ -340,7 +406,10 @@ static void Fiber_Profiler_Capture_callback(rb_event_flag_t event_flag, VALUE da
340
406
  if (!profiler->capture) return;
341
407
 
342
408
  if (event_flag_call_p(event_flag)) {
343
- struct Fiber_Profiler_Capture_Call *call = profiler_event_record_call(profiler, event_flag, id, klass);
409
+ struct Fiber_Profiler_Capture_Call *call = Fiber_Profiler_Capture_Call_new(profiler, event_flag, id, klass);
410
+
411
+ profiler->nesting += 1;
412
+
344
413
  Fiber_Profiler_Time_current(&call->enter_time);
345
414
  }
346
415
 
@@ -350,7 +419,7 @@ static void Fiber_Profiler_Capture_callback(rb_event_flag_t event_flag, VALUE da
350
419
  // We may encounter returns without a preceeding call. This isn't an error, but we should pretend like the call started at the beginning of the profiling session:
351
420
  if (call == NULL) {
352
421
  struct Fiber_Profiler_Capture_Call *last_call = Fiber_Profiler_Deque_last(&profiler->calls);
353
- call = profiler_event_record_call(profiler, event_flag, id, klass);
422
+ call = Fiber_Profiler_Capture_Call_new(profiler, event_flag, id, klass);
354
423
 
355
424
  if (last_call) {
356
425
  call->enter_time = last_call->enter_time;
@@ -359,19 +428,32 @@ static void Fiber_Profiler_Capture_callback(rb_event_flag_t event_flag, VALUE da
359
428
  }
360
429
  }
361
430
 
362
- Fiber_Profiler_Time_current(&call->exit_time);
431
+ call->duration = Fiber_Profiler_Time_delta_current(&call->enter_time);
363
432
 
364
433
  profiler->current = call->parent;
365
434
 
366
435
  // We may encounter returns without a preceeding call.
367
- if (profiler->nesting > 0)
368
- profiler->nesting -= 1;
436
+ profiler->nesting -= 1;
369
437
 
370
- // If the call was < 1% of the stall threshold, we can ignore it:
371
- double duration = Fiber_Profiler_Time_delta(&call->enter_time, &call->exit_time);
372
- if (duration < profiler->filter_threshold) {
373
- Fiber_Profiler_Deque_pop(&profiler->calls);
438
+ // We need to keep track of how deep the call stack goes:
439
+ if (profiler->nesting < profiler->nesting_minimum) {
440
+ profiler->nesting_minimum = profiler->nesting;
374
441
  }
442
+
443
+ Fiber_Profiler_Capture_Call_finish(profiler, call);
444
+ }
445
+
446
+ else {
447
+ struct Fiber_Profiler_Capture_Call *last_call = Fiber_Profiler_Deque_last(&profiler->calls);
448
+ struct Fiber_Profiler_Capture_Call *call = Fiber_Profiler_Capture_Call_new(profiler, event_flag, id, klass);
449
+
450
+ if (last_call) {
451
+ call->enter_time = last_call->enter_time;
452
+ } else {
453
+ call->enter_time = profiler->start_time;
454
+ }
455
+
456
+ call->duration = Fiber_Profiler_Time_delta_current(&call->enter_time);
375
457
  }
376
458
  }
377
459
 
@@ -395,9 +477,11 @@ void Fiber_Profiler_Capture_resume(VALUE self) {
395
477
  rb_event_flag_t event_flags = 0;
396
478
 
397
479
  if (profiler->track_calls) {
480
+ // event_flags |= RUBY_EVENT_LINE;
481
+
398
482
  event_flags |= RUBY_EVENT_CALL | RUBY_EVENT_RETURN;
399
483
  event_flags |= RUBY_EVENT_C_CALL | RUBY_EVENT_C_RETURN;
400
- // event_flags |= RUBY_EVENT_B_CALL | RUBY_EVENT_B_RETURN;
484
+ event_flags |= RUBY_EVENT_B_CALL | RUBY_EVENT_B_RETURN;
401
485
  }
402
486
 
403
487
  // CRuby will raise an exception if you try to add "INTERNAL_EVENT" hooks at the same time as other hooks, so we do it in two calls:
@@ -445,23 +529,21 @@ VALUE Fiber_Profiler_Capture_stop(VALUE self) {
445
529
  return self;
446
530
  }
447
531
 
448
- static inline float Fiber_Profiler_Capture_duration(struct Fiber_Profiler_Capture *profiler) {
449
- struct timespec duration;
450
-
451
- Fiber_Profiler_Time_current(&profiler->stop_time);
452
- Fiber_Profiler_Time_elapsed(&profiler->start_time, &profiler->stop_time, &duration);
453
-
454
- return Fiber_Profiler_Time_duration(&duration);
455
- }
456
-
457
532
  void Fiber_Profiler_Capture_finish(struct Fiber_Profiler_Capture *profiler) {
458
533
  profiler->capture = 0;
459
534
 
535
+ struct timespec stop_time;
536
+ Fiber_Profiler_Time_current(&stop_time);
537
+
460
538
  struct Fiber_Profiler_Capture_Call *current = profiler->current;
461
539
  while (current) {
462
- Fiber_Profiler_Time_current(&current->exit_time);
540
+ struct Fiber_Profiler_Capture_Call *parent = current->parent;
541
+
542
+ current->duration = Fiber_Profiler_Time_delta(&current->enter_time, &stop_time);
543
+
544
+ Fiber_Profiler_Capture_Call_finish(profiler, current);
463
545
 
464
- current = current->parent;
546
+ current = parent;
465
547
  }
466
548
  }
467
549
 
@@ -483,7 +565,8 @@ int Fiber_Profiler_Capture_sample(struct Fiber_Profiler_Capture *profiler) {
483
565
  void Fiber_Profiler_Capture_fiber_switch(VALUE self)
484
566
  {
485
567
  struct Fiber_Profiler_Capture *profiler = Fiber_Profiler_Capture_get(self);
486
- float duration = Fiber_Profiler_Capture_duration(profiler);
568
+ Fiber_Profiler_Time_current(&profiler->stop_time);
569
+ double duration = Fiber_Profiler_Time_delta(&profiler->start_time, &profiler->stop_time);
487
570
 
488
571
  if (profiler->capture) {
489
572
  Fiber_Profiler_Capture_pause(self);
@@ -506,57 +589,92 @@ void Fiber_Profiler_Capture_fiber_switch(VALUE self)
506
589
  }
507
590
  }
508
591
 
509
- static const float Fiber_Profiler_Capture_PRINT_MINIMUM_PROPORTION = 0.01;
592
+ // When sampling a fiber, we may encounter returns without a preceeding call. This isn't an error, and we should correctly visualize the call stack. We track both the relative nesting (which can be negative) and the minimum nesting level encountered during the profiling session, and use that to determine the absolute nesting level of each call when printing the call stack.
593
+ static size_t Fiber_Profiler_Capture_absolute_nesting(struct Fiber_Profiler_Capture *profiler, struct Fiber_Profiler_Capture_Call *call) {
594
+ return call->nesting - profiler->nesting_minimum;
595
+ }
596
+
597
+ // If a call is within this threshold of the parent call, it will be skipped when printing the call stack - it's considered inconsequential to the performance of the parent call.
598
+ static const double Fiber_Profiler_Capture_SKIP_THRESHOLD = 0.98;
510
599
 
511
600
  void Fiber_Profiler_Capture_print_tty(struct Fiber_Profiler_Capture *profiler, FILE *restrict stream) {
512
- struct timespec total_duration = {};
513
- Fiber_Profiler_Time_elapsed(&profiler->start_time, &profiler->stop_time, &total_duration);
601
+ double total_duration = Fiber_Profiler_Time_delta(&profiler->start_time, &profiler->stop_time);
514
602
 
515
- fprintf(stderr, "Fiber stalled for %.3f seconds\n", Fiber_Profiler_Time_duration(&total_duration));
603
+ fprintf(stderr, "## Fiber stalled for %.3f seconds ##\n", total_duration);
516
604
 
517
605
  size_t skipped = 0;
518
606
 
519
607
  Fiber_Profiler_Deque_each(&profiler->calls, struct Fiber_Profiler_Capture_Call, call) {
520
- struct timespec duration = {};
521
- Fiber_Profiler_Time_elapsed(&call->enter_time, &call->exit_time, &duration);
608
+ if (call->children) {
609
+ if (call->parent && call->parent->children == 1) {
610
+ if (call->duration > call->parent->duration * Fiber_Profiler_Capture_SKIP_THRESHOLD) {
611
+ if (!DEBUG_SKIPPED) {
612
+ // We remove the nesting level as we're skipping this call - and we use this to track the nesting of child calls which MAY be printed:
613
+ call->nesting = call->parent->nesting;
614
+ skipped += 1;
615
+ continue;
616
+ } else {
617
+ fprintf(stream, "\e[34m");
618
+ }
619
+ }
620
+ }
621
+ }
522
622
 
523
- // Skip calls that are too short to be meaningful:
524
- if (Fiber_Profiler_Time_proportion(&duration, &total_duration) < Fiber_Profiler_Capture_PRINT_MINIMUM_PROPORTION) {
623
+ if (call->parent) {
624
+ call->nesting = call->parent->nesting + 1;
625
+ }
626
+
627
+ if (skipped) {
628
+ fprintf(stream, "\e[2m");
525
629
 
526
- if (!DEBUG_SKIPPED) {
527
- skipped += 1;
528
- continue;
529
- } else {
530
- fprintf(stream, "\e[2m");
630
+ size_t nesting = Fiber_Profiler_Capture_absolute_nesting(profiler, call);
631
+ for (size_t i = 0; i < nesting; i += 1) {
632
+ fputc('\t', stream);
531
633
  }
634
+
635
+ fprintf(stream, "... skipped %zu nested calls ...\e[0m\n", skipped);
636
+
637
+ skipped = 0;
638
+ call->nesting += 1;
532
639
  }
533
640
 
534
- for (size_t i = 0; i < call->nesting; i += 1) {
641
+ size_t nesting = Fiber_Profiler_Capture_absolute_nesting(profiler, call);
642
+ for (size_t i = 0; i < nesting; i += 1) {
535
643
  fputc('\t', stream);
536
644
  }
537
645
 
646
+ if (Fiber_Profiler_Capture_Call_expensive_p(call, total_duration)) {
647
+ fprintf(stream, "\e[31m");
648
+ }
649
+
538
650
  VALUE class_inspect = rb_inspect(call->klass);
539
651
  const char *name = rb_id2name(call->id);
540
652
 
541
- fprintf(stream, "%s:%d in %s '%s#%s' (" Fiber_Profiler_TIME_PRINTF_TIMESPEC "s)\n", call->path, call->line, event_flag_name(call->event_flag), RSTRING_PTR(class_inspect), name, Fiber_Profiler_TIME_PRINTF_TIMESPEC_ARGUMENTS(duration));
653
+ struct timespec offset;
654
+ Fiber_Profiler_Time_elapsed(&profiler->start_time, &call->enter_time, &offset);
655
+
656
+ fprintf(stream, "%s:%d in %s '%s#%s' (%0.4fs, T+" Fiber_Profiler_TIME_PRINTF_TIMESPEC ")\n", call->path, call->line, event_flag_name(call->event_flag), RSTRING_PTR(class_inspect), name, call->duration, Fiber_Profiler_TIME_PRINTF_TIMESPEC_ARGUMENTS(offset));
542
657
 
543
- if (DEBUG_SKIPPED) {
544
- fprintf(stream, "\e[0m");
658
+ fprintf(stream, "\e[0m");
659
+
660
+ if (call->filtered) {
661
+ fprintf(stream, "\e[2m");
662
+
663
+ for (size_t i = 0; i < nesting + 1; i += 1) {
664
+ fputc('\t', stream);
665
+ }
666
+
667
+ fprintf(stream, "... filtered %zu direct calls ...\e[0m\n", call->filtered);
545
668
  }
546
669
  }
547
-
548
- if (skipped > 0) {
549
- fprintf(stream, "Skipped %zu calls that were too short to be meaningful.\n", skipped);
550
- }
551
670
  }
552
671
 
553
672
  void Fiber_Profiler_Capture_print_json(struct Fiber_Profiler_Capture *profiler, FILE *restrict stream) {
554
- struct timespec total_duration = {};
555
- Fiber_Profiler_Time_elapsed(&profiler->start_time, &profiler->stop_time, &total_duration);
673
+ double total_duration = Fiber_Profiler_Time_delta(&profiler->start_time, &profiler->stop_time);
556
674
 
557
675
  fputc('{', stream);
558
676
 
559
- fprintf(stream, "\"duration\":" Fiber_Profiler_TIME_PRINTF_TIMESPEC, Fiber_Profiler_TIME_PRINTF_TIMESPEC_ARGUMENTS(total_duration));
677
+ fprintf(stream, "\"duration\":%0.6f", total_duration);
560
678
 
561
679
  size_t skipped = 0;
562
680
 
@@ -564,20 +682,32 @@ void Fiber_Profiler_Capture_print_json(struct Fiber_Profiler_Capture *profiler,
564
682
  int first = 1;
565
683
 
566
684
  Fiber_Profiler_Deque_each(&profiler->calls, struct Fiber_Profiler_Capture_Call, call) {
567
- struct timespec duration = {};
568
- Fiber_Profiler_Time_elapsed(&call->enter_time, &call->exit_time, &duration);
685
+ if (call->children) {
686
+ if (call->parent && call->parent->children == 1) {
687
+ if (call->duration > call->parent->duration * Fiber_Profiler_Capture_SKIP_THRESHOLD) {
688
+ // We remove the nesting level as we're skipping this call - and we use this to track the nesting of child calls which MAY be printed:
689
+ call->nesting = call->parent->nesting;
690
+ skipped += 1;
691
+ continue;
692
+ }
693
+ }
694
+ }
569
695
 
570
- // Skip calls that are too short to be meaningful:
571
- if (Fiber_Profiler_Time_proportion(&duration, &total_duration) < Fiber_Profiler_Capture_PRINT_MINIMUM_PROPORTION) {
572
- skipped += 1;
573
- continue;
696
+ if (call->parent) {
697
+ call->nesting = call->parent->nesting + 1;
574
698
  }
575
699
 
576
700
  VALUE class_inspect = rb_inspect(call->klass);
577
701
  const char *name = rb_id2name(call->id);
578
702
 
579
- fprintf(stream, "%s{\"path\":\"%s\",\"line\":%d,\"class\":\"%s\",\"method\":\"%s\",\"duration\":" Fiber_Profiler_TIME_PRINTF_TIMESPEC ",\"nesting\":%zu}", first ? "" : ",", call->path, call->line, RSTRING_PTR(class_inspect), name, Fiber_Profiler_TIME_PRINTF_TIMESPEC_ARGUMENTS(duration), call->nesting);
703
+ size_t nesting = Fiber_Profiler_Capture_absolute_nesting(profiler, call);
704
+
705
+ struct timespec offset;
706
+ Fiber_Profiler_Time_elapsed(&profiler->start_time, &call->enter_time, &offset);
707
+
708
+ fprintf(stream, "%s{\"path\":\"%s\",\"line\":%d,\"class\":\"%s\",\"method\":\"%s\",\"duration\":%0.6f,\"offset\":" Fiber_Profiler_TIME_PRINTF_TIMESPEC ",\"nesting\":%zu,\"skipped\":%zu,\"filtered\":%zu}", first ? "" : ",", call->path, call->line, RSTRING_PTR(class_inspect), name, call->duration, Fiber_Profiler_TIME_PRINTF_TIMESPEC_ARGUMENTS(offset), nesting, skipped, call->filtered);
580
709
 
710
+ skipped = 0;
581
711
  first = 0;
582
712
  }
583
713
 
@@ -11,7 +11,7 @@ enum {
11
11
  #ifdef RUBY_DEBUG
12
12
  Fiber_Profiler_Deque_DEBUG = 1,
13
13
  #else
14
- Fiber_Profiler_Deque_DEBUG = 0,
14
+ Fiber_Profiler_Deque_DEBUG = 1,
15
15
  #endif
16
16
  };
17
17
 
@@ -172,6 +172,53 @@ inline static size_t Fiber_Profiler_Deque_default_capacity(struct Fiber_Profiler
172
172
  return (target_size - sizeof(struct Fiber_Profiler_Deque_Page)) / deque->element_size;
173
173
  }
174
174
 
175
+ static inline void Fiber_Profiler_Deque_reserve(struct Fiber_Profiler_Deque *deque, size_t capacity)
176
+ {
177
+ struct Fiber_Profiler_Deque_Page *page = deque->head;
178
+
179
+ // Walk over all the pages and see if we have enough capacity:
180
+ while (page) {
181
+ size_t available = page->capacity - page->size;
182
+
183
+ if (available > capacity) {
184
+ return;
185
+ }
186
+
187
+ capacity -= available;
188
+
189
+ if (page->tail) {
190
+ page = page->tail;
191
+ } else {
192
+ break;
193
+ }
194
+ }
195
+
196
+ // We need to allocate a new page:
197
+ size_t minimum_capacity = Fiber_Profiler_Deque_default_capacity(deque);
198
+ if (capacity < minimum_capacity) {
199
+ capacity = minimum_capacity;
200
+ }
201
+
202
+ struct Fiber_Profiler_Deque_Page *reserved_page = Fiber_Profiler_Deque_Page_allocate(deque->element_size, capacity);
203
+ if (reserved_page == NULL) {
204
+ return;
205
+ }
206
+
207
+ if (page) {
208
+ page->tail = reserved_page;
209
+ reserved_page->head = page;
210
+ } else {
211
+ deque->head = deque->tail = reserved_page;
212
+ }
213
+
214
+ if (Fiber_Profiler_Deque_DEBUG) Fiber_Profiler_Deque_debug(deque, __FUNCTION__);
215
+ }
216
+
217
+ static inline void Fiber_Profiler_Deque_reserve_default(struct Fiber_Profiler_Deque *deque)
218
+ {
219
+ Fiber_Profiler_Deque_reserve(deque, Fiber_Profiler_Deque_default_capacity(deque));
220
+ }
221
+
175
222
  void *Fiber_Profiler_Deque_push(struct Fiber_Profiler_Deque *deque)
176
223
  {
177
224
  struct Fiber_Profiler_Deque_Page *page = deque->tail;
@@ -13,23 +13,3 @@ void Fiber_Profiler_Time_elapsed(const struct timespec* start, const struct time
13
13
  duration->tv_nsec = stop->tv_nsec - start->tv_nsec;
14
14
  }
15
15
  }
16
-
17
- double Fiber_Profiler_Time_duration(const struct timespec *duration)
18
- {
19
- return duration->tv_sec + duration->tv_nsec / 1000000000.0;
20
- }
21
-
22
- void Fiber_Profiler_Time_current(struct timespec *time) {
23
- clock_gettime(CLOCK_MONOTONIC, time);
24
- }
25
-
26
- double Fiber_Profiler_Time_proportion(const struct timespec *duration, const struct timespec *total_duration) {
27
- return Fiber_Profiler_Time_duration(duration) / Fiber_Profiler_Time_duration(total_duration);
28
- }
29
-
30
- double Fiber_Profiler_Time_delta(const struct timespec *start, const struct timespec *stop) {
31
- struct timespec duration;
32
- Fiber_Profiler_Time_elapsed(start, stop, &duration);
33
-
34
- return Fiber_Profiler_Time_duration(&duration);
35
- }
@@ -7,11 +7,34 @@
7
7
  #include <time.h>
8
8
 
9
9
  void Fiber_Profiler_Time_elapsed(const struct timespec* start, const struct timespec* stop, struct timespec *duration);
10
- double Fiber_Profiler_Time_duration(const struct timespec *duration);
11
- void Fiber_Profiler_Time_current(struct timespec *time);
12
10
 
13
- double Fiber_Profiler_Time_delta(const struct timespec *start, const struct timespec *stop);
14
- double Fiber_Profiler_Time_proportion(const struct timespec *duration, const struct timespec *total_duration);
11
+ static inline double Fiber_Profiler_Time_duration(const struct timespec *duration)
12
+ {
13
+ return duration->tv_sec + duration->tv_nsec / 1000000000.0;
14
+ }
15
+
16
+ static inline double Fiber_Profiler_Time_proportion(const struct timespec *duration, const struct timespec *total_duration)
17
+ {
18
+ return Fiber_Profiler_Time_duration(duration) / Fiber_Profiler_Time_duration(total_duration);
19
+ }
20
+
21
+ static inline void Fiber_Profiler_Time_current(struct timespec *time)
22
+ {
23
+ clock_gettime(CLOCK_MONOTONIC, time);
24
+ }
25
+
26
+ static inline double Fiber_Profiler_Time_delta(const struct timespec *start, const struct timespec *stop)
27
+ {
28
+ return stop->tv_sec - start->tv_sec + (stop->tv_nsec - start->tv_nsec) / 1e9;
29
+ }
30
+
31
+ static inline double Fiber_Profiler_Time_delta_current(const struct timespec *start)
32
+ {
33
+ struct timespec stop;
34
+ Fiber_Profiler_Time_current(&stop);
35
+
36
+ return Fiber_Profiler_Time_delta(start, &stop);
37
+ }
15
38
 
16
39
  #define Fiber_Profiler_TIME_PRINTF_TIMESPEC "%.3g"
17
40
  #define Fiber_Profiler_TIME_PRINTF_TIMESPEC_ARGUMENTS(ts) ((double)(ts).tv_sec + (ts).tv_nsec / 1e9)
data/ext/fiber.o ADDED
Binary file
data/ext/profiler.o ADDED
Binary file
data/ext/time.o ADDED
Binary file
@@ -7,6 +7,6 @@
7
7
  class Fiber
8
8
  # @namespace
9
9
  module Profiler
10
- VERSION = "0.1.3"
10
+ VERSION = "0.1.4"
11
11
  end
12
12
  end
data.tar.gz.sig CHANGED
Binary file
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: fiber-profiler
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.3
4
+ version: 0.1.4
5
5
  platform: ruby
6
6
  authors:
7
7
  - Samuel Williams
@@ -43,7 +43,15 @@ extensions:
43
43
  - ext/extconf.rb
44
44
  extra_rdoc_files: []
45
45
  files:
46
+ - ext/Fiber_Profiler.bundle
47
+ - ext/Fiber_Profiler.bundle.dSYM/Contents/Info.plist
48
+ - ext/Fiber_Profiler.bundle.dSYM/Contents/Resources/DWARF/Fiber_Profiler.bundle
49
+ - ext/Fiber_Profiler.bundle.dSYM/Contents/Resources/Relocations/aarch64/Fiber_Profiler.bundle.yml
50
+ - ext/Makefile
51
+ - ext/capture.o
52
+ - ext/extconf.h
46
53
  - ext/extconf.rb
54
+ - ext/fiber.o
47
55
  - ext/fiber/profiler/capture.c
48
56
  - ext/fiber/profiler/capture.h
49
57
  - ext/fiber/profiler/deque.h
@@ -53,6 +61,8 @@ files:
53
61
  - ext/fiber/profiler/profiler.h
54
62
  - ext/fiber/profiler/time.c
55
63
  - ext/fiber/profiler/time.h
64
+ - ext/profiler.o
65
+ - ext/time.o
56
66
  - lib/fiber/profiler.rb
57
67
  - lib/fiber/profiler/capture.rb
58
68
  - lib/fiber/profiler/native.rb
metadata.gz.sig CHANGED
Binary file