2 #include <mono/utils/mono-compiler.h>
5 #include "mini-runtime.h"
6 #include <mono/utils/mono-counters.h>
7 #include <mono/utils/mono-logger-internals.h>
9 #ifdef ENABLE_EXPERIMENT_TIERED
11 MiniTieredStats mini_tiered_stats
;
13 static MonoCoopCond compilation_wait
;
14 static MonoCoopMutex compilation_mutex
;
18 static GSList
*compilation_queue
[NUM_TIERS
];
19 static CallsitePatcher patchers
[NUM_TIERS
] = { NULL
};
21 static const char* const patch_kind_str
[] = {
26 static GHashTable
*callsites_hash
[TIERED_PATCH_KIND_NUM
] = { NULL
};
28 /* TODO: use scientific methods (TM) to determine values */
29 static const int threshold
[NUM_TIERS
] = {
35 compiler_thread (void)
37 MonoInternalThread
*internal
= mono_thread_internal_current ();
38 internal
->state
|= ThreadState_Background
;
39 internal
->flags
|= MONO_THREAD_FLAG_DONT_MANAGE
;
41 mono_native_thread_set_name (mono_native_thread_id_get (), "Tiered Compilation Thread");
44 mono_coop_cond_wait (&compilation_wait
, &compilation_mutex
);
46 for (int tier_level
= 0; tier_level
< NUM_TIERS
; tier_level
++) {
47 GSList
*ppcs
= compilation_queue
[tier_level
];
48 compilation_queue
[tier_level
] = NULL
;
50 for (GSList
*ppc_
= ppcs
; ppc_
!= NULL
; ppc_
= ppc_
->next
) {
51 MiniTieredPatchPointContext
*ppc
= (MiniTieredPatchPointContext
*) ppc_
->data
;
53 for (int patch_kind
= 0; patch_kind
< TIERED_PATCH_KIND_NUM
; patch_kind
++) {
54 if (!callsites_hash
[patch_kind
])
57 GSList
*patchsites
= g_hash_table_lookup (callsites_hash
[patch_kind
], ppc
->target_method
);
59 for (; patchsites
!= NULL
; patchsites
= patchsites
->next
) {
60 gpointer patchsite
= (gpointer
) patchsites
->data
;
62 mono_trace (G_LOG_LEVEL_DEBUG
, MONO_TRACE_TIERED
, "tiered: patching %p with patch_kind=%s @ tier_level=%d", patchsite
, patch_kind_str
[patch_kind
], tier_level
);
63 mono_trace (G_LOG_LEVEL_DEBUG
, MONO_TRACE_TIERED
, "\t-> caller=%s", mono_pmip (patchsite
));
64 mono_trace (G_LOG_LEVEL_DEBUG
, MONO_TRACE_TIERED
, "\t-> callee=%s", mono_method_full_name (ppc
->target_method
, TRUE
));
66 gboolean success
= patchers
[patch_kind
] (ppc
, patchsite
);
69 mono_trace (G_LOG_LEVEL_WARNING
, MONO_TRACE_TIERED
, "tiered: couldn't patch %p with target %s, dropping it.", patchsite
, mono_method_full_name (ppc
->target_method
, TRUE
));
71 g_hash_table_remove (callsites_hash
[patch_kind
], ppc
->target_method
);
72 g_slist_free (patchsites
);
78 mono_coop_mutex_unlock (&compilation_mutex
);
83 mini_tiered_init (void)
87 mono_counters_init ();
88 mono_counters_register ("Methods promoted", MONO_COUNTER_TIERED
| MONO_COUNTER_LONG
, &mini_tiered_stats
.methods_promoted
);
90 mono_coop_cond_init (&compilation_wait
);
91 mono_coop_mutex_init (&compilation_mutex
);
93 mono_thread_create_internal (mono_domain_get (), compiler_thread
, NULL
, MONO_THREAD_CREATE_FLAGS_THREADPOOL
, error
);
94 mono_error_assert_ok (error
);
98 mini_tiered_register_callsite_patcher (CallsitePatcher func
, int level
)
100 g_assert (level
< NUM_TIERS
);
102 patchers
[level
] = func
;
106 mini_tiered_record_callsite (gpointer ip
, MonoMethod
*target_method
, int patch_kind
)
108 if (!callsites_hash
[patch_kind
])
109 callsites_hash
[patch_kind
] = g_hash_table_new (NULL
, NULL
);
111 GSList
*patchsites
= g_hash_table_lookup (callsites_hash
[patch_kind
], target_method
);
112 patchsites
= g_slist_prepend (patchsites
, ip
);
113 g_hash_table_insert (callsites_hash
[patch_kind
], target_method
, patchsites
);
117 mini_tiered_inc (MonoDomain
*domain
, MonoMethod
*method
, MiniTieredCounter
*tcnt
, int tier_level
)
119 if (G_UNLIKELY (tcnt
->hotness
== threshold
[tier_level
] && !tcnt
->promoted
)) {
120 tcnt
->promoted
= TRUE
;
121 mini_tiered_stats
.methods_promoted
++;
123 mono_trace (G_LOG_LEVEL_DEBUG
, MONO_TRACE_TIERED
, "tiered: queued %s", mono_method_full_name (method
, TRUE
));
125 MiniTieredPatchPointContext
*ppc
= g_new0 (MiniTieredPatchPointContext
, 1);
126 ppc
->domain
= domain
;
127 ppc
->target_method
= method
;
128 ppc
->tier_level
= tier_level
;
130 mono_coop_mutex_lock (&compilation_mutex
);
131 compilation_queue
[tier_level
] = g_slist_append (compilation_queue
[tier_level
], ppc
);
132 mono_coop_mutex_unlock (&compilation_mutex
);
133 mono_coop_cond_signal (&compilation_wait
);
134 } else if (!tcnt
->promoted
) {
135 /* FIXME: inline that into caller */
140 MONO_EMPTY_SOURCE_FILE (tiered
);