collect \f[I]NUM\f[] frames at the most.
The default is 8.
.IP \[bu] 2
+\f[I]maxsamples=NUM\f[]: stop allocating reusable sample events
+once \f[I]NUM\f[] events have been allocated (a value of zero for
+all intents and purposes means unlimited). By default, the value
+of this setting is the number of CPU cores multiplied by 1000. This
+is usually a good enough value for typical desktop and mobile apps.
+If you're losing too many samples due to this default (which is
+possible in apps with an unusually high amount of threads), you
+may want to tinker with this value to find a good balance between
+sample hit rate and performance impact on the app. The way it works
+is that sample events are enqueued for reuse after they're flushed
+to the output file; if a thread gets a sampling signal but there are
+no sample events in the reuse queue and the profiler has reached the
+maximum number of sample allocations, the sample gets dropped. So a
+higher number for this setting will increase the chance that a
+thread is able to collect a sample, but also necessarily means that
+there will be more work done by the profiler. You can run Mono with
+the \f[I]--stats\f[] option to see statistics about sample events.
+.IP \[bu] 2
\f[I]calldepth=NUM\f[]: ignore method enter/leave events when the
call chain depth is bigger than NUM.
.IP \[bu] 2
static int do_coverage = 0;
static gboolean debug_coverage = FALSE;
static MonoProfileSamplingMode sampling_mode = MONO_PROFILER_STAT_MODE_PROCESS;
+static int max_allocated_sample_hits;
static gint32 sample_hits;
static gint32 sample_flushes;
SampleHit *sample = (SampleHit *) mono_lock_free_queue_dequeue (&profiler->sample_reuse_queue);
if (!sample) {
+ /*
+ * If we're out of reusable sample events and we're not allowed to
+ * allocate more, we have no choice but to drop the event.
+ */
+ if (InterlockedRead (&sample_allocations) >= max_allocated_sample_hits)
+ return;
+
sample = mono_lock_free_alloc (&profiler->sample_allocator);
sample->prof = profiler;
}
}
-#if USE_PERF_EVENTS
-
static int
mono_cpu_count (void)
{
return 1;
}
+#if USE_PERF_EVENTS
+
typedef struct {
int perf_fd;
unsigned int prev_pos;
MONO_PROFILE_INS_COVERAGE|MONO_PROFILE_APPDOMAIN_EVENTS|MONO_PROFILE_CONTEXT_EVENTS|
MONO_PROFILE_ASSEMBLY_EVENTS;
+ max_allocated_sample_hits = mono_cpu_count () * 1000;
+
mono_counters_register ("Sample hits", MONO_COUNTER_UINT | MONO_COUNTER_PROFILER | MONO_COUNTER_MONOTONIC, &sample_hits);
mono_counters_register ("Sample flushes", MONO_COUNTER_UINT | MONO_COUNTER_PROFILER | MONO_COUNTER_MONOTONIC, &sample_flushes);
mono_counters_register ("Sample events allocated", MONO_COUNTER_UINT | MONO_COUNTER_PROFILER | MONO_COUNTER_MONOTONIC, &sample_allocations);
notraces = num_frames == 0;
continue;
}
+ if ((opt = match_option (p, "maxsamples", &val)) != p) {
+ char *end;
+ max_allocated_sample_hits = strtoul (val, &end, 10);
+ if (!max_allocated_sample_hits)
+ max_allocated_sample_hits = G_MAXINT32;
+ free (val);
+ continue;
+ }
if ((opt = match_option (p, "calldepth", &val)) != p) {
char *end;
max_call_depth = strtoul (val, &end, 10);