mirror of
https://github.com/dart-lang/sdk
synced 2024-10-14 15:21:54 +00:00
[vm] Lock-free management of the profiler's sample blocks.
Add asserts against using mutexes or monitors during the signal handler or suspended thread scopes. Poison use of Thread::Current during these scopes. TEST=ci Bug: https://github.com/dart-lang/sdk/issues/51124 Change-Id: If1df06520114105b2b4d8c81b4650bdb4efeaf50 Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/283703 Reviewed-by: Ben Konyi <bkonyi@google.com> Commit-Queue: Ryan Macnak <rmacnak@google.com>
This commit is contained in:
parent
f56c45eb37
commit
347c49354e
|
@ -198,20 +198,20 @@ static constexpr dart::compiler::target::word ICData_entries_offset = 12;
|
|||
static constexpr dart::compiler::target::word ICData_owner_offset = 20;
|
||||
static constexpr dart::compiler::target::word ICData_state_bits_offset = 28;
|
||||
static constexpr dart::compiler::target::word Int32x4_value_offset = 8;
|
||||
static constexpr dart::compiler::target::word Isolate_current_tag_offset = 24;
|
||||
static constexpr dart::compiler::target::word Isolate_default_tag_offset = 28;
|
||||
static constexpr dart::compiler::target::word Isolate_finalizers_offset = 40;
|
||||
static constexpr dart::compiler::target::word Isolate_current_tag_offset = 20;
|
||||
static constexpr dart::compiler::target::word Isolate_default_tag_offset = 24;
|
||||
static constexpr dart::compiler::target::word Isolate_finalizers_offset = 36;
|
||||
static constexpr dart::compiler::target::word
|
||||
Isolate_has_resumption_breakpoints_offset = 45;
|
||||
static constexpr dart::compiler::target::word Isolate_ic_miss_code_offset = 32;
|
||||
Isolate_has_resumption_breakpoints_offset = 41;
|
||||
static constexpr dart::compiler::target::word Isolate_ic_miss_code_offset = 28;
|
||||
static constexpr dart::compiler::target::word IsolateGroup_object_store_offset =
|
||||
16;
|
||||
static constexpr dart::compiler::target::word IsolateGroup_class_table_offset =
|
||||
8;
|
||||
static constexpr dart::compiler::target::word
|
||||
IsolateGroup_cached_class_table_table_offset = 12;
|
||||
static constexpr dart::compiler::target::word Isolate_single_step_offset = 44;
|
||||
static constexpr dart::compiler::target::word Isolate_user_tag_offset = 20;
|
||||
static constexpr dart::compiler::target::word Isolate_single_step_offset = 40;
|
||||
static constexpr dart::compiler::target::word Isolate_user_tag_offset = 16;
|
||||
static constexpr dart::compiler::target::word LinkedHashBase_data_offset = 12;
|
||||
static constexpr dart::compiler::target::word
|
||||
ImmutableLinkedHashBase_data_offset = 12;
|
||||
|
@ -877,20 +877,20 @@ static constexpr dart::compiler::target::word ICData_entries_offset = 24;
|
|||
static constexpr dart::compiler::target::word ICData_owner_offset = 40;
|
||||
static constexpr dart::compiler::target::word ICData_state_bits_offset = 52;
|
||||
static constexpr dart::compiler::target::word Int32x4_value_offset = 8;
|
||||
static constexpr dart::compiler::target::word Isolate_current_tag_offset = 48;
|
||||
static constexpr dart::compiler::target::word Isolate_default_tag_offset = 56;
|
||||
static constexpr dart::compiler::target::word Isolate_finalizers_offset = 80;
|
||||
static constexpr dart::compiler::target::word Isolate_current_tag_offset = 40;
|
||||
static constexpr dart::compiler::target::word Isolate_default_tag_offset = 48;
|
||||
static constexpr dart::compiler::target::word Isolate_finalizers_offset = 72;
|
||||
static constexpr dart::compiler::target::word
|
||||
Isolate_has_resumption_breakpoints_offset = 89;
|
||||
static constexpr dart::compiler::target::word Isolate_ic_miss_code_offset = 64;
|
||||
Isolate_has_resumption_breakpoints_offset = 81;
|
||||
static constexpr dart::compiler::target::word Isolate_ic_miss_code_offset = 56;
|
||||
static constexpr dart::compiler::target::word IsolateGroup_object_store_offset =
|
||||
32;
|
||||
static constexpr dart::compiler::target::word IsolateGroup_class_table_offset =
|
||||
16;
|
||||
static constexpr dart::compiler::target::word
|
||||
IsolateGroup_cached_class_table_table_offset = 24;
|
||||
static constexpr dart::compiler::target::word Isolate_single_step_offset = 88;
|
||||
static constexpr dart::compiler::target::word Isolate_user_tag_offset = 40;
|
||||
static constexpr dart::compiler::target::word Isolate_single_step_offset = 80;
|
||||
static constexpr dart::compiler::target::word Isolate_user_tag_offset = 32;
|
||||
static constexpr dart::compiler::target::word LinkedHashBase_data_offset = 24;
|
||||
static constexpr dart::compiler::target::word
|
||||
ImmutableLinkedHashBase_data_offset = 24;
|
||||
|
@ -1561,20 +1561,20 @@ static constexpr dart::compiler::target::word ICData_entries_offset = 12;
|
|||
static constexpr dart::compiler::target::word ICData_owner_offset = 20;
|
||||
static constexpr dart::compiler::target::word ICData_state_bits_offset = 28;
|
||||
static constexpr dart::compiler::target::word Int32x4_value_offset = 8;
|
||||
static constexpr dart::compiler::target::word Isolate_current_tag_offset = 24;
|
||||
static constexpr dart::compiler::target::word Isolate_default_tag_offset = 28;
|
||||
static constexpr dart::compiler::target::word Isolate_finalizers_offset = 40;
|
||||
static constexpr dart::compiler::target::word Isolate_current_tag_offset = 20;
|
||||
static constexpr dart::compiler::target::word Isolate_default_tag_offset = 24;
|
||||
static constexpr dart::compiler::target::word Isolate_finalizers_offset = 36;
|
||||
static constexpr dart::compiler::target::word
|
||||
Isolate_has_resumption_breakpoints_offset = 45;
|
||||
static constexpr dart::compiler::target::word Isolate_ic_miss_code_offset = 32;
|
||||
Isolate_has_resumption_breakpoints_offset = 41;
|
||||
static constexpr dart::compiler::target::word Isolate_ic_miss_code_offset = 28;
|
||||
static constexpr dart::compiler::target::word IsolateGroup_object_store_offset =
|
||||
16;
|
||||
static constexpr dart::compiler::target::word IsolateGroup_class_table_offset =
|
||||
8;
|
||||
static constexpr dart::compiler::target::word
|
||||
IsolateGroup_cached_class_table_table_offset = 12;
|
||||
static constexpr dart::compiler::target::word Isolate_single_step_offset = 44;
|
||||
static constexpr dart::compiler::target::word Isolate_user_tag_offset = 20;
|
||||
static constexpr dart::compiler::target::word Isolate_single_step_offset = 40;
|
||||
static constexpr dart::compiler::target::word Isolate_user_tag_offset = 16;
|
||||
static constexpr dart::compiler::target::word LinkedHashBase_data_offset = 12;
|
||||
static constexpr dart::compiler::target::word
|
||||
ImmutableLinkedHashBase_data_offset = 12;
|
||||
|
@ -2240,20 +2240,20 @@ static constexpr dart::compiler::target::word ICData_entries_offset = 24;
|
|||
static constexpr dart::compiler::target::word ICData_owner_offset = 40;
|
||||
static constexpr dart::compiler::target::word ICData_state_bits_offset = 52;
|
||||
static constexpr dart::compiler::target::word Int32x4_value_offset = 8;
|
||||
static constexpr dart::compiler::target::word Isolate_current_tag_offset = 48;
|
||||
static constexpr dart::compiler::target::word Isolate_default_tag_offset = 56;
|
||||
static constexpr dart::compiler::target::word Isolate_finalizers_offset = 80;
|
||||
static constexpr dart::compiler::target::word Isolate_current_tag_offset = 40;
|
||||
static constexpr dart::compiler::target::word Isolate_default_tag_offset = 48;
|
||||
static constexpr dart::compiler::target::word Isolate_finalizers_offset = 72;
|
||||
static constexpr dart::compiler::target::word
|
||||
Isolate_has_resumption_breakpoints_offset = 89;
|
||||
static constexpr dart::compiler::target::word Isolate_ic_miss_code_offset = 64;
|
||||
Isolate_has_resumption_breakpoints_offset = 81;
|
||||
static constexpr dart::compiler::target::word Isolate_ic_miss_code_offset = 56;
|
||||
static constexpr dart::compiler::target::word IsolateGroup_object_store_offset =
|
||||
32;
|
||||
static constexpr dart::compiler::target::word IsolateGroup_class_table_offset =
|
||||
16;
|
||||
static constexpr dart::compiler::target::word
|
||||
IsolateGroup_cached_class_table_table_offset = 24;
|
||||
static constexpr dart::compiler::target::word Isolate_single_step_offset = 88;
|
||||
static constexpr dart::compiler::target::word Isolate_user_tag_offset = 40;
|
||||
static constexpr dart::compiler::target::word Isolate_single_step_offset = 80;
|
||||
static constexpr dart::compiler::target::word Isolate_user_tag_offset = 32;
|
||||
static constexpr dart::compiler::target::word LinkedHashBase_data_offset = 24;
|
||||
static constexpr dart::compiler::target::word
|
||||
ImmutableLinkedHashBase_data_offset = 24;
|
||||
|
@ -2925,20 +2925,20 @@ static constexpr dart::compiler::target::word ICData_entries_offset = 24;
|
|||
static constexpr dart::compiler::target::word ICData_owner_offset = 40;
|
||||
static constexpr dart::compiler::target::word ICData_state_bits_offset = 52;
|
||||
static constexpr dart::compiler::target::word Int32x4_value_offset = 8;
|
||||
static constexpr dart::compiler::target::word Isolate_current_tag_offset = 48;
|
||||
static constexpr dart::compiler::target::word Isolate_default_tag_offset = 56;
|
||||
static constexpr dart::compiler::target::word Isolate_finalizers_offset = 80;
|
||||
static constexpr dart::compiler::target::word Isolate_current_tag_offset = 40;
|
||||
static constexpr dart::compiler::target::word Isolate_default_tag_offset = 48;
|
||||
static constexpr dart::compiler::target::word Isolate_finalizers_offset = 72;
|
||||
static constexpr dart::compiler::target::word
|
||||
Isolate_has_resumption_breakpoints_offset = 89;
|
||||
static constexpr dart::compiler::target::word Isolate_ic_miss_code_offset = 64;
|
||||
Isolate_has_resumption_breakpoints_offset = 81;
|
||||
static constexpr dart::compiler::target::word Isolate_ic_miss_code_offset = 56;
|
||||
static constexpr dart::compiler::target::word IsolateGroup_object_store_offset =
|
||||
32;
|
||||
static constexpr dart::compiler::target::word IsolateGroup_class_table_offset =
|
||||
16;
|
||||
static constexpr dart::compiler::target::word
|
||||
IsolateGroup_cached_class_table_table_offset = 24;
|
||||
static constexpr dart::compiler::target::word Isolate_single_step_offset = 88;
|
||||
static constexpr dart::compiler::target::word Isolate_user_tag_offset = 40;
|
||||
static constexpr dart::compiler::target::word Isolate_single_step_offset = 80;
|
||||
static constexpr dart::compiler::target::word Isolate_user_tag_offset = 32;
|
||||
static constexpr dart::compiler::target::word LinkedHashBase_data_offset = 16;
|
||||
static constexpr dart::compiler::target::word
|
||||
ImmutableLinkedHashBase_data_offset = 16;
|
||||
|
@ -3610,20 +3610,20 @@ static constexpr dart::compiler::target::word ICData_entries_offset = 24;
|
|||
static constexpr dart::compiler::target::word ICData_owner_offset = 40;
|
||||
static constexpr dart::compiler::target::word ICData_state_bits_offset = 52;
|
||||
static constexpr dart::compiler::target::word Int32x4_value_offset = 8;
|
||||
static constexpr dart::compiler::target::word Isolate_current_tag_offset = 48;
|
||||
static constexpr dart::compiler::target::word Isolate_default_tag_offset = 56;
|
||||
static constexpr dart::compiler::target::word Isolate_finalizers_offset = 80;
|
||||
static constexpr dart::compiler::target::word Isolate_current_tag_offset = 40;
|
||||
static constexpr dart::compiler::target::word Isolate_default_tag_offset = 48;
|
||||
static constexpr dart::compiler::target::word Isolate_finalizers_offset = 72;
|
||||
static constexpr dart::compiler::target::word
|
||||
Isolate_has_resumption_breakpoints_offset = 89;
|
||||
static constexpr dart::compiler::target::word Isolate_ic_miss_code_offset = 64;
|
||||
Isolate_has_resumption_breakpoints_offset = 81;
|
||||
static constexpr dart::compiler::target::word Isolate_ic_miss_code_offset = 56;
|
||||
static constexpr dart::compiler::target::word IsolateGroup_object_store_offset =
|
||||
32;
|
||||
static constexpr dart::compiler::target::word IsolateGroup_class_table_offset =
|
||||
16;
|
||||
static constexpr dart::compiler::target::word
|
||||
IsolateGroup_cached_class_table_table_offset = 24;
|
||||
static constexpr dart::compiler::target::word Isolate_single_step_offset = 88;
|
||||
static constexpr dart::compiler::target::word Isolate_user_tag_offset = 40;
|
||||
static constexpr dart::compiler::target::word Isolate_single_step_offset = 80;
|
||||
static constexpr dart::compiler::target::word Isolate_user_tag_offset = 32;
|
||||
static constexpr dart::compiler::target::word LinkedHashBase_data_offset = 16;
|
||||
static constexpr dart::compiler::target::word
|
||||
ImmutableLinkedHashBase_data_offset = 16;
|
||||
|
@ -4296,20 +4296,20 @@ static constexpr dart::compiler::target::word ICData_entries_offset = 12;
|
|||
static constexpr dart::compiler::target::word ICData_owner_offset = 20;
|
||||
static constexpr dart::compiler::target::word ICData_state_bits_offset = 28;
|
||||
static constexpr dart::compiler::target::word Int32x4_value_offset = 8;
|
||||
static constexpr dart::compiler::target::word Isolate_current_tag_offset = 24;
|
||||
static constexpr dart::compiler::target::word Isolate_default_tag_offset = 28;
|
||||
static constexpr dart::compiler::target::word Isolate_finalizers_offset = 40;
|
||||
static constexpr dart::compiler::target::word Isolate_current_tag_offset = 20;
|
||||
static constexpr dart::compiler::target::word Isolate_default_tag_offset = 24;
|
||||
static constexpr dart::compiler::target::word Isolate_finalizers_offset = 36;
|
||||
static constexpr dart::compiler::target::word
|
||||
Isolate_has_resumption_breakpoints_offset = 45;
|
||||
static constexpr dart::compiler::target::word Isolate_ic_miss_code_offset = 32;
|
||||
Isolate_has_resumption_breakpoints_offset = 41;
|
||||
static constexpr dart::compiler::target::word Isolate_ic_miss_code_offset = 28;
|
||||
static constexpr dart::compiler::target::word IsolateGroup_object_store_offset =
|
||||
16;
|
||||
static constexpr dart::compiler::target::word IsolateGroup_class_table_offset =
|
||||
8;
|
||||
static constexpr dart::compiler::target::word
|
||||
IsolateGroup_cached_class_table_table_offset = 12;
|
||||
static constexpr dart::compiler::target::word Isolate_single_step_offset = 44;
|
||||
static constexpr dart::compiler::target::word Isolate_user_tag_offset = 20;
|
||||
static constexpr dart::compiler::target::word Isolate_single_step_offset = 40;
|
||||
static constexpr dart::compiler::target::word Isolate_user_tag_offset = 16;
|
||||
static constexpr dart::compiler::target::word LinkedHashBase_data_offset = 12;
|
||||
static constexpr dart::compiler::target::word
|
||||
ImmutableLinkedHashBase_data_offset = 12;
|
||||
|
@ -4977,20 +4977,20 @@ static constexpr dart::compiler::target::word ICData_entries_offset = 24;
|
|||
static constexpr dart::compiler::target::word ICData_owner_offset = 40;
|
||||
static constexpr dart::compiler::target::word ICData_state_bits_offset = 52;
|
||||
static constexpr dart::compiler::target::word Int32x4_value_offset = 8;
|
||||
static constexpr dart::compiler::target::word Isolate_current_tag_offset = 48;
|
||||
static constexpr dart::compiler::target::word Isolate_default_tag_offset = 56;
|
||||
static constexpr dart::compiler::target::word Isolate_finalizers_offset = 80;
|
||||
static constexpr dart::compiler::target::word Isolate_current_tag_offset = 40;
|
||||
static constexpr dart::compiler::target::word Isolate_default_tag_offset = 48;
|
||||
static constexpr dart::compiler::target::word Isolate_finalizers_offset = 72;
|
||||
static constexpr dart::compiler::target::word
|
||||
Isolate_has_resumption_breakpoints_offset = 89;
|
||||
static constexpr dart::compiler::target::word Isolate_ic_miss_code_offset = 64;
|
||||
Isolate_has_resumption_breakpoints_offset = 81;
|
||||
static constexpr dart::compiler::target::word Isolate_ic_miss_code_offset = 56;
|
||||
static constexpr dart::compiler::target::word IsolateGroup_object_store_offset =
|
||||
32;
|
||||
static constexpr dart::compiler::target::word IsolateGroup_class_table_offset =
|
||||
16;
|
||||
static constexpr dart::compiler::target::word
|
||||
IsolateGroup_cached_class_table_table_offset = 24;
|
||||
static constexpr dart::compiler::target::word Isolate_single_step_offset = 88;
|
||||
static constexpr dart::compiler::target::word Isolate_user_tag_offset = 40;
|
||||
static constexpr dart::compiler::target::word Isolate_single_step_offset = 80;
|
||||
static constexpr dart::compiler::target::word Isolate_user_tag_offset = 32;
|
||||
static constexpr dart::compiler::target::word LinkedHashBase_data_offset = 24;
|
||||
static constexpr dart::compiler::target::word
|
||||
ImmutableLinkedHashBase_data_offset = 24;
|
||||
|
@ -11078,15 +11078,15 @@ static constexpr dart::compiler::target::word AOT_ICData_owner_offset = 16;
|
|||
static constexpr dart::compiler::target::word AOT_ICData_state_bits_offset = 20;
|
||||
static constexpr dart::compiler::target::word AOT_Int32x4_value_offset = 8;
|
||||
static constexpr dart::compiler::target::word AOT_Isolate_current_tag_offset =
|
||||
24;
|
||||
20;
|
||||
static constexpr dart::compiler::target::word AOT_Isolate_default_tag_offset =
|
||||
28;
|
||||
24;
|
||||
static constexpr dart::compiler::target::word AOT_Isolate_finalizers_offset =
|
||||
40;
|
||||
36;
|
||||
static constexpr dart::compiler::target::word
|
||||
AOT_Isolate_has_resumption_breakpoints_offset = 45;
|
||||
AOT_Isolate_has_resumption_breakpoints_offset = 41;
|
||||
static constexpr dart::compiler::target::word AOT_Isolate_ic_miss_code_offset =
|
||||
32;
|
||||
28;
|
||||
static constexpr dart::compiler::target::word
|
||||
AOT_IsolateGroup_object_store_offset = 16;
|
||||
static constexpr dart::compiler::target::word
|
||||
|
@ -11094,8 +11094,8 @@ static constexpr dart::compiler::target::word
|
|||
static constexpr dart::compiler::target::word
|
||||
AOT_IsolateGroup_cached_class_table_table_offset = 12;
|
||||
static constexpr dart::compiler::target::word AOT_Isolate_single_step_offset =
|
||||
44;
|
||||
static constexpr dart::compiler::target::word AOT_Isolate_user_tag_offset = 20;
|
||||
40;
|
||||
static constexpr dart::compiler::target::word AOT_Isolate_user_tag_offset = 16;
|
||||
static constexpr dart::compiler::target::word AOT_LinkedHashBase_data_offset =
|
||||
12;
|
||||
static constexpr dart::compiler::target::word
|
||||
|
@ -11831,15 +11831,15 @@ static constexpr dart::compiler::target::word AOT_ICData_owner_offset = 32;
|
|||
static constexpr dart::compiler::target::word AOT_ICData_state_bits_offset = 40;
|
||||
static constexpr dart::compiler::target::word AOT_Int32x4_value_offset = 8;
|
||||
static constexpr dart::compiler::target::word AOT_Isolate_current_tag_offset =
|
||||
48;
|
||||
40;
|
||||
static constexpr dart::compiler::target::word AOT_Isolate_default_tag_offset =
|
||||
56;
|
||||
48;
|
||||
static constexpr dart::compiler::target::word AOT_Isolate_finalizers_offset =
|
||||
80;
|
||||
72;
|
||||
static constexpr dart::compiler::target::word
|
||||
AOT_Isolate_has_resumption_breakpoints_offset = 89;
|
||||
AOT_Isolate_has_resumption_breakpoints_offset = 81;
|
||||
static constexpr dart::compiler::target::word AOT_Isolate_ic_miss_code_offset =
|
||||
64;
|
||||
56;
|
||||
static constexpr dart::compiler::target::word
|
||||
AOT_IsolateGroup_object_store_offset = 32;
|
||||
static constexpr dart::compiler::target::word
|
||||
|
@ -11847,8 +11847,8 @@ static constexpr dart::compiler::target::word
|
|||
static constexpr dart::compiler::target::word
|
||||
AOT_IsolateGroup_cached_class_table_table_offset = 24;
|
||||
static constexpr dart::compiler::target::word AOT_Isolate_single_step_offset =
|
||||
88;
|
||||
static constexpr dart::compiler::target::word AOT_Isolate_user_tag_offset = 40;
|
||||
80;
|
||||
static constexpr dart::compiler::target::word AOT_Isolate_user_tag_offset = 32;
|
||||
static constexpr dart::compiler::target::word AOT_LinkedHashBase_data_offset =
|
||||
24;
|
||||
static constexpr dart::compiler::target::word
|
||||
|
@ -12591,15 +12591,15 @@ static constexpr dart::compiler::target::word AOT_ICData_owner_offset = 32;
|
|||
static constexpr dart::compiler::target::word AOT_ICData_state_bits_offset = 40;
|
||||
static constexpr dart::compiler::target::word AOT_Int32x4_value_offset = 8;
|
||||
static constexpr dart::compiler::target::word AOT_Isolate_current_tag_offset =
|
||||
48;
|
||||
40;
|
||||
static constexpr dart::compiler::target::word AOT_Isolate_default_tag_offset =
|
||||
56;
|
||||
48;
|
||||
static constexpr dart::compiler::target::word AOT_Isolate_finalizers_offset =
|
||||
80;
|
||||
72;
|
||||
static constexpr dart::compiler::target::word
|
||||
AOT_Isolate_has_resumption_breakpoints_offset = 89;
|
||||
AOT_Isolate_has_resumption_breakpoints_offset = 81;
|
||||
static constexpr dart::compiler::target::word AOT_Isolate_ic_miss_code_offset =
|
||||
64;
|
||||
56;
|
||||
static constexpr dart::compiler::target::word
|
||||
AOT_IsolateGroup_object_store_offset = 32;
|
||||
static constexpr dart::compiler::target::word
|
||||
|
@ -12607,8 +12607,8 @@ static constexpr dart::compiler::target::word
|
|||
static constexpr dart::compiler::target::word
|
||||
AOT_IsolateGroup_cached_class_table_table_offset = 24;
|
||||
static constexpr dart::compiler::target::word AOT_Isolate_single_step_offset =
|
||||
88;
|
||||
static constexpr dart::compiler::target::word AOT_Isolate_user_tag_offset = 40;
|
||||
80;
|
||||
static constexpr dart::compiler::target::word AOT_Isolate_user_tag_offset = 32;
|
||||
static constexpr dart::compiler::target::word AOT_LinkedHashBase_data_offset =
|
||||
24;
|
||||
static constexpr dart::compiler::target::word
|
||||
|
@ -13349,15 +13349,15 @@ static constexpr dart::compiler::target::word AOT_ICData_owner_offset = 32;
|
|||
static constexpr dart::compiler::target::word AOT_ICData_state_bits_offset = 40;
|
||||
static constexpr dart::compiler::target::word AOT_Int32x4_value_offset = 8;
|
||||
static constexpr dart::compiler::target::word AOT_Isolate_current_tag_offset =
|
||||
48;
|
||||
40;
|
||||
static constexpr dart::compiler::target::word AOT_Isolate_default_tag_offset =
|
||||
56;
|
||||
48;
|
||||
static constexpr dart::compiler::target::word AOT_Isolate_finalizers_offset =
|
||||
80;
|
||||
72;
|
||||
static constexpr dart::compiler::target::word
|
||||
AOT_Isolate_has_resumption_breakpoints_offset = 89;
|
||||
AOT_Isolate_has_resumption_breakpoints_offset = 81;
|
||||
static constexpr dart::compiler::target::word AOT_Isolate_ic_miss_code_offset =
|
||||
64;
|
||||
56;
|
||||
static constexpr dart::compiler::target::word
|
||||
AOT_IsolateGroup_object_store_offset = 32;
|
||||
static constexpr dart::compiler::target::word
|
||||
|
@ -13365,8 +13365,8 @@ static constexpr dart::compiler::target::word
|
|||
static constexpr dart::compiler::target::word
|
||||
AOT_IsolateGroup_cached_class_table_table_offset = 24;
|
||||
static constexpr dart::compiler::target::word AOT_Isolate_single_step_offset =
|
||||
88;
|
||||
static constexpr dart::compiler::target::word AOT_Isolate_user_tag_offset = 40;
|
||||
80;
|
||||
static constexpr dart::compiler::target::word AOT_Isolate_user_tag_offset = 32;
|
||||
static constexpr dart::compiler::target::word AOT_LinkedHashBase_data_offset =
|
||||
16;
|
||||
static constexpr dart::compiler::target::word
|
||||
|
@ -14107,15 +14107,15 @@ static constexpr dart::compiler::target::word AOT_ICData_owner_offset = 32;
|
|||
static constexpr dart::compiler::target::word AOT_ICData_state_bits_offset = 40;
|
||||
static constexpr dart::compiler::target::word AOT_Int32x4_value_offset = 8;
|
||||
static constexpr dart::compiler::target::word AOT_Isolate_current_tag_offset =
|
||||
48;
|
||||
40;
|
||||
static constexpr dart::compiler::target::word AOT_Isolate_default_tag_offset =
|
||||
56;
|
||||
48;
|
||||
static constexpr dart::compiler::target::word AOT_Isolate_finalizers_offset =
|
||||
80;
|
||||
72;
|
||||
static constexpr dart::compiler::target::word
|
||||
AOT_Isolate_has_resumption_breakpoints_offset = 89;
|
||||
AOT_Isolate_has_resumption_breakpoints_offset = 81;
|
||||
static constexpr dart::compiler::target::word AOT_Isolate_ic_miss_code_offset =
|
||||
64;
|
||||
56;
|
||||
static constexpr dart::compiler::target::word
|
||||
AOT_IsolateGroup_object_store_offset = 32;
|
||||
static constexpr dart::compiler::target::word
|
||||
|
@ -14123,8 +14123,8 @@ static constexpr dart::compiler::target::word
|
|||
static constexpr dart::compiler::target::word
|
||||
AOT_IsolateGroup_cached_class_table_table_offset = 24;
|
||||
static constexpr dart::compiler::target::word AOT_Isolate_single_step_offset =
|
||||
88;
|
||||
static constexpr dart::compiler::target::word AOT_Isolate_user_tag_offset = 40;
|
||||
80;
|
||||
static constexpr dart::compiler::target::word AOT_Isolate_user_tag_offset = 32;
|
||||
static constexpr dart::compiler::target::word AOT_LinkedHashBase_data_offset =
|
||||
16;
|
||||
static constexpr dart::compiler::target::word
|
||||
|
@ -14865,15 +14865,15 @@ static constexpr dart::compiler::target::word AOT_ICData_owner_offset = 16;
|
|||
static constexpr dart::compiler::target::word AOT_ICData_state_bits_offset = 20;
|
||||
static constexpr dart::compiler::target::word AOT_Int32x4_value_offset = 8;
|
||||
static constexpr dart::compiler::target::word AOT_Isolate_current_tag_offset =
|
||||
24;
|
||||
20;
|
||||
static constexpr dart::compiler::target::word AOT_Isolate_default_tag_offset =
|
||||
28;
|
||||
24;
|
||||
static constexpr dart::compiler::target::word AOT_Isolate_finalizers_offset =
|
||||
40;
|
||||
36;
|
||||
static constexpr dart::compiler::target::word
|
||||
AOT_Isolate_has_resumption_breakpoints_offset = 45;
|
||||
AOT_Isolate_has_resumption_breakpoints_offset = 41;
|
||||
static constexpr dart::compiler::target::word AOT_Isolate_ic_miss_code_offset =
|
||||
32;
|
||||
28;
|
||||
static constexpr dart::compiler::target::word
|
||||
AOT_IsolateGroup_object_store_offset = 16;
|
||||
static constexpr dart::compiler::target::word
|
||||
|
@ -14881,8 +14881,8 @@ static constexpr dart::compiler::target::word
|
|||
static constexpr dart::compiler::target::word
|
||||
AOT_IsolateGroup_cached_class_table_table_offset = 12;
|
||||
static constexpr dart::compiler::target::word AOT_Isolate_single_step_offset =
|
||||
44;
|
||||
static constexpr dart::compiler::target::word AOT_Isolate_user_tag_offset = 20;
|
||||
40;
|
||||
static constexpr dart::compiler::target::word AOT_Isolate_user_tag_offset = 16;
|
||||
static constexpr dart::compiler::target::word AOT_LinkedHashBase_data_offset =
|
||||
12;
|
||||
static constexpr dart::compiler::target::word
|
||||
|
@ -15620,15 +15620,15 @@ static constexpr dart::compiler::target::word AOT_ICData_owner_offset = 32;
|
|||
static constexpr dart::compiler::target::word AOT_ICData_state_bits_offset = 40;
|
||||
static constexpr dart::compiler::target::word AOT_Int32x4_value_offset = 8;
|
||||
static constexpr dart::compiler::target::word AOT_Isolate_current_tag_offset =
|
||||
48;
|
||||
40;
|
||||
static constexpr dart::compiler::target::word AOT_Isolate_default_tag_offset =
|
||||
56;
|
||||
48;
|
||||
static constexpr dart::compiler::target::word AOT_Isolate_finalizers_offset =
|
||||
80;
|
||||
72;
|
||||
static constexpr dart::compiler::target::word
|
||||
AOT_Isolate_has_resumption_breakpoints_offset = 89;
|
||||
AOT_Isolate_has_resumption_breakpoints_offset = 81;
|
||||
static constexpr dart::compiler::target::word AOT_Isolate_ic_miss_code_offset =
|
||||
64;
|
||||
56;
|
||||
static constexpr dart::compiler::target::word
|
||||
AOT_IsolateGroup_object_store_offset = 32;
|
||||
static constexpr dart::compiler::target::word
|
||||
|
@ -15636,8 +15636,8 @@ static constexpr dart::compiler::target::word
|
|||
static constexpr dart::compiler::target::word
|
||||
AOT_IsolateGroup_cached_class_table_table_offset = 24;
|
||||
static constexpr dart::compiler::target::word AOT_Isolate_single_step_offset =
|
||||
88;
|
||||
static constexpr dart::compiler::target::word AOT_Isolate_user_tag_offset = 40;
|
||||
80;
|
||||
static constexpr dart::compiler::target::word AOT_Isolate_user_tag_offset = 32;
|
||||
static constexpr dart::compiler::target::word AOT_LinkedHashBase_data_offset =
|
||||
24;
|
||||
static constexpr dart::compiler::target::word
|
||||
|
|
|
@ -2382,97 +2382,6 @@ void Isolate::Run() {
|
|||
reinterpret_cast<uword>(this));
|
||||
}
|
||||
|
||||
#if !defined(PRODUCT)
|
||||
void Isolate::set_current_sample_block(SampleBlock* current) {
|
||||
ASSERT(current_sample_block_lock_.IsOwnedByCurrentThread());
|
||||
if (current != nullptr) {
|
||||
current->set_is_allocation_block(false);
|
||||
current->set_owner(this);
|
||||
}
|
||||
current_sample_block_ = current;
|
||||
}
|
||||
|
||||
void Isolate::set_current_allocation_sample_block(SampleBlock* current) {
|
||||
if (current != nullptr) {
|
||||
current->set_is_allocation_block(true);
|
||||
current->set_owner(this);
|
||||
}
|
||||
current_allocation_sample_block_ = current;
|
||||
}
|
||||
|
||||
void Isolate::FreeSampleBlock(SampleBlock* block) {
|
||||
if (block == nullptr) {
|
||||
return;
|
||||
}
|
||||
SampleBlock* head;
|
||||
// We're pushing the freed sample block to the front of the free_block_list_,
|
||||
// which means the last element of the list will be the oldest freed sample.
|
||||
do {
|
||||
head = free_block_list_.load(std::memory_order_acquire);
|
||||
block->next_free_ = head;
|
||||
} while (!free_block_list_.compare_exchange_weak(head, block,
|
||||
std::memory_order_release));
|
||||
}
|
||||
|
||||
class StreamableSampleFilter : public SampleFilter {
|
||||
public:
|
||||
explicit StreamableSampleFilter(Dart_Port port)
|
||||
: SampleFilter(port, kNoTaskFilter, -1, -1) {}
|
||||
|
||||
bool FilterSample(Sample* sample) override {
|
||||
const UserTag& tag =
|
||||
UserTag::Handle(UserTag::FindTagById(sample->user_tag()));
|
||||
return tag.streamable();
|
||||
}
|
||||
};
|
||||
|
||||
void Isolate::ProcessFreeSampleBlocks(Thread* thread) {
|
||||
SampleBlock* head = free_block_list_.exchange(nullptr);
|
||||
if (head == nullptr) {
|
||||
// No sample blocks to process.
|
||||
return;
|
||||
}
|
||||
// Reverse the list before processing so older blocks are streamed and reused
|
||||
// first.
|
||||
SampleBlock* reversed_head = nullptr;
|
||||
do {
|
||||
SampleBlock* next = head->next_free_;
|
||||
if (reversed_head == nullptr) {
|
||||
reversed_head = head;
|
||||
reversed_head->next_free_ = nullptr;
|
||||
} else {
|
||||
head->next_free_ = reversed_head;
|
||||
reversed_head = head;
|
||||
}
|
||||
head = next;
|
||||
} while (head != nullptr);
|
||||
head = reversed_head;
|
||||
if (Service::profiler_stream.enabled() && !IsSystemIsolate(this)) {
|
||||
StackZone zone(thread);
|
||||
SampleBlockListProcessor buffer(head);
|
||||
if (buffer.HasStreamableSamples(thread)) {
|
||||
HandleScope handle_scope(thread);
|
||||
StreamableSampleFilter filter(main_port());
|
||||
Profile profile;
|
||||
profile.Build(thread, &filter, &buffer);
|
||||
ASSERT(profile.sample_count() > 0);
|
||||
ServiceEvent event(this, ServiceEvent::kCpuSamples);
|
||||
event.set_cpu_profile(&profile);
|
||||
Service::HandleEvent(&event);
|
||||
}
|
||||
}
|
||||
|
||||
do {
|
||||
SampleBlock* next = head->next_free_;
|
||||
head->next_free_ = nullptr;
|
||||
head->evictable_ = true;
|
||||
Profiler::sample_block_buffer()->FreeBlock(head);
|
||||
head = next;
|
||||
thread->CheckForSafepoint();
|
||||
} while (head != nullptr);
|
||||
}
|
||||
#endif // !defined(PRODUCT)
|
||||
|
||||
void Isolate::RunAndCleanupFinalizersOnShutdown() {
|
||||
if (finalizers_ == GrowableObjectArray::null()) return;
|
||||
|
||||
|
@ -2616,25 +2525,7 @@ void Isolate::Shutdown() {
|
|||
ServiceIsolate::SendIsolateShutdownMessage();
|
||||
#if !defined(PRODUCT)
|
||||
debugger()->Shutdown();
|
||||
// Cleanup profiler state.
|
||||
SampleBlock* cpu_block = current_sample_block();
|
||||
if (cpu_block != nullptr) {
|
||||
cpu_block->release_block();
|
||||
}
|
||||
SampleBlock* allocation_block = current_allocation_sample_block();
|
||||
if (allocation_block != nullptr) {
|
||||
allocation_block->release_block();
|
||||
}
|
||||
|
||||
// Process the previously assigned sample blocks if we're using the
|
||||
// profiler's sample buffer. Some tests create their own SampleBlockBuffer
|
||||
// and handle block processing themselves.
|
||||
if ((cpu_block != nullptr || allocation_block != nullptr) &&
|
||||
Profiler::sample_block_buffer() != nullptr) {
|
||||
StackZone zone(thread);
|
||||
HandleScope handle_scope(thread);
|
||||
Profiler::sample_block_buffer()->ProcessCompletedBlocks();
|
||||
}
|
||||
Profiler::IsolateShutdown(thread);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
|
|
@ -1130,33 +1130,27 @@ class Isolate : public BaseIsolate, public IntrusiveDListEntry<Isolate> {
|
|||
#if !defined(PRODUCT)
|
||||
Debugger* debugger() const { return debugger_; }
|
||||
|
||||
// NOTE: this lock should only be acquired within the profiler signal handler.
|
||||
Mutex* current_sample_block_lock() const {
|
||||
return const_cast<Mutex*>(¤t_sample_block_lock_);
|
||||
}
|
||||
|
||||
// Returns the current SampleBlock used to track CPU profiling samples.
|
||||
//
|
||||
// NOTE: current_sample_block_lock() should be held when accessing this
|
||||
// block.
|
||||
SampleBlock* current_sample_block() const { return current_sample_block_; }
|
||||
void set_current_sample_block(SampleBlock* current);
|
||||
|
||||
void FreeSampleBlock(SampleBlock* block);
|
||||
void ProcessFreeSampleBlocks(Thread* thread);
|
||||
bool should_process_blocks() const {
|
||||
return free_block_list_.load(std::memory_order_relaxed) != nullptr;
|
||||
void set_current_sample_block(SampleBlock* block) {
|
||||
current_sample_block_ = block;
|
||||
}
|
||||
std::atomic<SampleBlock*> free_block_list_ = nullptr;
|
||||
void ProcessFreeSampleBlocks(Thread* thread);
|
||||
|
||||
// Returns the current SampleBlock used to track Dart allocation samples.
|
||||
//
|
||||
// Allocations should only occur on the mutator thread for an isolate, so we
|
||||
// don't need to worry about grabbing a lock while accessing this block.
|
||||
SampleBlock* current_allocation_sample_block() const {
|
||||
return current_allocation_sample_block_;
|
||||
}
|
||||
void set_current_allocation_sample_block(SampleBlock* current);
|
||||
void set_current_allocation_sample_block(SampleBlock* block) {
|
||||
current_allocation_sample_block_ = block;
|
||||
}
|
||||
|
||||
bool TakeHasCompletedBlocks() {
|
||||
return has_completed_blocks_.exchange(0) != 0;
|
||||
}
|
||||
bool TrySetHasCompletedBlocks() {
|
||||
return has_completed_blocks_.exchange(1) == 0;
|
||||
}
|
||||
|
||||
void set_single_step(bool value) { single_step_ = value; }
|
||||
bool single_step() const { return single_step_; }
|
||||
|
@ -1637,18 +1631,12 @@ class Isolate : public BaseIsolate, public IntrusiveDListEntry<Isolate> {
|
|||
Debugger* debugger_ = nullptr;
|
||||
|
||||
// SampleBlock containing CPU profiling samples.
|
||||
//
|
||||
// Can be accessed by multiple threads, so current_sample_block_lock_ should
|
||||
// be acquired before accessing.
|
||||
SampleBlock* current_sample_block_ = nullptr;
|
||||
Mutex current_sample_block_lock_;
|
||||
RelaxedAtomic<SampleBlock*> current_sample_block_ = nullptr;
|
||||
|
||||
// SampleBlock containing Dart allocation profiling samples.
|
||||
//
|
||||
// Allocations should only occur on the mutator thread for an isolate, so we
|
||||
// shouldn't need to worry about grabbing a lock for the allocation sample
|
||||
// block.
|
||||
SampleBlock* current_allocation_sample_block_ = nullptr;
|
||||
RelaxedAtomic<SampleBlock*> current_allocation_sample_block_ = nullptr;
|
||||
|
||||
RelaxedAtomic<uword> has_completed_blocks_ = {0};
|
||||
|
||||
int64_t last_resume_timestamp_;
|
||||
|
||||
|
|
|
@ -21,6 +21,9 @@ Mutex* OSThread::thread_list_lock_ = NULL;
|
|||
bool OSThread::creation_enabled_ = false;
|
||||
|
||||
thread_local ThreadState* OSThread::current_vm_thread_ = NULL;
|
||||
#if defined(DEBUG)
|
||||
thread_local bool ThreadInterruptScope::in_thread_interrupt_scope_ = false;
|
||||
#endif
|
||||
|
||||
#if defined(SUPPORT_TIMELINE)
|
||||
inline void UpdateTimelineTrackMetadata(const OSThread& thread) {
|
||||
|
|
|
@ -173,6 +173,11 @@ class OSThread : public BaseThread {
|
|||
static void SetCurrent(OSThread* current) { SetCurrentTLS(current); }
|
||||
|
||||
static ThreadState* CurrentVMThread() { return current_vm_thread_; }
|
||||
#if defined(DEBUG)
|
||||
static void SetCurrentVMThread(ThreadState* thread) {
|
||||
current_vm_thread_ = thread;
|
||||
}
|
||||
#endif
|
||||
|
||||
// TODO(5411455): Use flag to override default value and Validate the
|
||||
// stack size by querying OS.
|
||||
|
@ -382,6 +387,35 @@ inline bool Mutex::IsOwnedByCurrentThread() const {
|
|||
#endif
|
||||
}
|
||||
|
||||
// Mark when we are running in a signal handler (Linux, Android) or with a
|
||||
// suspended thread (Windows, Mac, Fuchia). During this time, we cannot take
|
||||
// locks, access Thread/Isolate::Current(), or use malloc.
|
||||
class ThreadInterruptScope : public ValueObject {
|
||||
#if defined(DEBUG)
|
||||
public:
|
||||
ThreadInterruptScope() {
|
||||
ASSERT(!in_thread_interrupt_scope_); // We don't use nested signals.
|
||||
in_thread_interrupt_scope_ = true;
|
||||
|
||||
// Poison attempts to use Thread::Current. This is much cheaper than adding
|
||||
// an assert in Thread::Current itself.
|
||||
saved_current_vm_thread_ = OSThread::CurrentVMThread();
|
||||
OSThread::SetCurrentVMThread(reinterpret_cast<ThreadState*>(0xabababab));
|
||||
}
|
||||
|
||||
~ThreadInterruptScope() {
|
||||
OSThread::SetCurrentVMThread(saved_current_vm_thread_);
|
||||
in_thread_interrupt_scope_ = false;
|
||||
}
|
||||
|
||||
static bool in_thread_interrupt_scope() { return in_thread_interrupt_scope_; }
|
||||
|
||||
private:
|
||||
ThreadState* saved_current_vm_thread_;
|
||||
static thread_local bool in_thread_interrupt_scope_;
|
||||
#endif // DEBUG
|
||||
};
|
||||
|
||||
} // namespace dart
|
||||
|
||||
#endif // RUNTIME_VM_OS_THREAD_H_
|
||||
|
|
|
@ -327,6 +327,8 @@ Mutex::~Mutex() {
|
|||
}
|
||||
|
||||
void Mutex::Lock() {
|
||||
DEBUG_ASSERT(!ThreadInterruptScope::in_thread_interrupt_scope());
|
||||
|
||||
int result = pthread_mutex_lock(data_.mutex());
|
||||
// Specifically check for dead lock to help debugging.
|
||||
ASSERT(result != EDEADLK);
|
||||
|
@ -338,6 +340,8 @@ void Mutex::Lock() {
|
|||
}
|
||||
|
||||
bool Mutex::TryLock() {
|
||||
DEBUG_ASSERT(!ThreadInterruptScope::in_thread_interrupt_scope());
|
||||
|
||||
int result = pthread_mutex_trylock(data_.mutex());
|
||||
// Return false if the lock is busy and locking failed.
|
||||
if (result == EBUSY) {
|
||||
|
@ -409,6 +413,8 @@ Monitor::~Monitor() {
|
|||
}
|
||||
|
||||
bool Monitor::TryEnter() {
|
||||
DEBUG_ASSERT(!ThreadInterruptScope::in_thread_interrupt_scope());
|
||||
|
||||
int result = pthread_mutex_trylock(data_.mutex());
|
||||
// Return false if the lock is busy and locking failed.
|
||||
if (result == EBUSY) {
|
||||
|
@ -424,6 +430,8 @@ bool Monitor::TryEnter() {
|
|||
}
|
||||
|
||||
void Monitor::Enter() {
|
||||
DEBUG_ASSERT(!ThreadInterruptScope::in_thread_interrupt_scope());
|
||||
|
||||
int result = pthread_mutex_lock(data_.mutex());
|
||||
VALIDATE_PTHREAD_RESULT(result);
|
||||
|
||||
|
|
|
@ -328,6 +328,8 @@ Mutex::~Mutex() {
|
|||
}
|
||||
|
||||
void Mutex::Lock() {
|
||||
DEBUG_ASSERT(!ThreadInterruptScope::in_thread_interrupt_scope());
|
||||
|
||||
int result = pthread_mutex_lock(data_.mutex());
|
||||
// Specifically check for dead lock to help debugging.
|
||||
ASSERT(result != EDEADLK);
|
||||
|
@ -339,6 +341,8 @@ void Mutex::Lock() {
|
|||
}
|
||||
|
||||
bool Mutex::TryLock() {
|
||||
DEBUG_ASSERT(!ThreadInterruptScope::in_thread_interrupt_scope());
|
||||
|
||||
int result = pthread_mutex_trylock(data_.mutex());
|
||||
// Return false if the lock is busy and locking failed.
|
||||
if (result == EBUSY) {
|
||||
|
@ -413,6 +417,8 @@ Monitor::~Monitor() {
|
|||
}
|
||||
|
||||
bool Monitor::TryEnter() {
|
||||
DEBUG_ASSERT(!ThreadInterruptScope::in_thread_interrupt_scope());
|
||||
|
||||
int result = pthread_mutex_trylock(data_.mutex());
|
||||
// Return false if the lock is busy and locking failed.
|
||||
if (result == EBUSY) {
|
||||
|
@ -428,6 +434,8 @@ bool Monitor::TryEnter() {
|
|||
}
|
||||
|
||||
void Monitor::Enter() {
|
||||
DEBUG_ASSERT(!ThreadInterruptScope::in_thread_interrupt_scope());
|
||||
|
||||
int result = pthread_mutex_lock(data_.mutex());
|
||||
VALIDATE_PTHREAD_RESULT(result);
|
||||
|
||||
|
|
|
@ -330,6 +330,8 @@ Mutex::~Mutex() {
|
|||
}
|
||||
|
||||
void Mutex::Lock() {
|
||||
DEBUG_ASSERT(!ThreadInterruptScope::in_thread_interrupt_scope());
|
||||
|
||||
int result = pthread_mutex_lock(data_.mutex());
|
||||
// Specifically check for dead lock to help debugging.
|
||||
ASSERT(result != EDEADLK);
|
||||
|
@ -341,6 +343,8 @@ void Mutex::Lock() {
|
|||
}
|
||||
|
||||
bool Mutex::TryLock() {
|
||||
DEBUG_ASSERT(!ThreadInterruptScope::in_thread_interrupt_scope());
|
||||
|
||||
int result = pthread_mutex_trylock(data_.mutex());
|
||||
// Return false if the lock is busy and locking failed.
|
||||
if (result == EBUSY) {
|
||||
|
@ -415,6 +419,8 @@ Monitor::~Monitor() {
|
|||
}
|
||||
|
||||
bool Monitor::TryEnter() {
|
||||
DEBUG_ASSERT(!ThreadInterruptScope::in_thread_interrupt_scope());
|
||||
|
||||
int result = pthread_mutex_trylock(data_.mutex());
|
||||
// Return false if the lock is busy and locking failed.
|
||||
if (result == EBUSY) {
|
||||
|
@ -430,6 +436,8 @@ bool Monitor::TryEnter() {
|
|||
}
|
||||
|
||||
void Monitor::Enter() {
|
||||
DEBUG_ASSERT(!ThreadInterruptScope::in_thread_interrupt_scope());
|
||||
|
||||
int result = pthread_mutex_lock(data_.mutex());
|
||||
VALIDATE_PTHREAD_RESULT(result);
|
||||
|
||||
|
|
|
@ -298,6 +298,8 @@ Mutex::~Mutex() {
|
|||
}
|
||||
|
||||
void Mutex::Lock() {
|
||||
DEBUG_ASSERT(!ThreadInterruptScope::in_thread_interrupt_scope());
|
||||
|
||||
int result = pthread_mutex_lock(data_.mutex());
|
||||
// Specifically check for dead lock to help debugging.
|
||||
ASSERT(result != EDEADLK);
|
||||
|
@ -309,6 +311,8 @@ void Mutex::Lock() {
|
|||
}
|
||||
|
||||
bool Mutex::TryLock() {
|
||||
DEBUG_ASSERT(!ThreadInterruptScope::in_thread_interrupt_scope());
|
||||
|
||||
int result = pthread_mutex_trylock(data_.mutex());
|
||||
// Return false if the lock is busy and locking failed.
|
||||
if ((result == EBUSY) || (result == EDEADLK)) {
|
||||
|
@ -373,6 +377,8 @@ Monitor::~Monitor() {
|
|||
}
|
||||
|
||||
bool Monitor::TryEnter() {
|
||||
DEBUG_ASSERT(!ThreadInterruptScope::in_thread_interrupt_scope());
|
||||
|
||||
int result = pthread_mutex_trylock(data_.mutex());
|
||||
// Return false if the lock is busy and locking failed.
|
||||
if ((result == EBUSY) || (result == EDEADLK)) {
|
||||
|
@ -388,6 +394,8 @@ bool Monitor::TryEnter() {
|
|||
}
|
||||
|
||||
void Monitor::Enter() {
|
||||
DEBUG_ASSERT(!ThreadInterruptScope::in_thread_interrupt_scope());
|
||||
|
||||
int result = pthread_mutex_lock(data_.mutex());
|
||||
VALIDATE_PTHREAD_RESULT(result);
|
||||
|
||||
|
|
|
@ -247,6 +247,8 @@ Mutex::~Mutex() {
|
|||
}
|
||||
|
||||
void Mutex::Lock() {
|
||||
DEBUG_ASSERT(!ThreadInterruptScope::in_thread_interrupt_scope());
|
||||
|
||||
AcquireSRWLockExclusive(&data_.lock_);
|
||||
#if defined(DEBUG)
|
||||
// When running with assertions enabled we do track the owner.
|
||||
|
@ -255,6 +257,8 @@ void Mutex::Lock() {
|
|||
}
|
||||
|
||||
bool Mutex::TryLock() {
|
||||
DEBUG_ASSERT(!ThreadInterruptScope::in_thread_interrupt_scope());
|
||||
|
||||
if (TryAcquireSRWLockExclusive(&data_.lock_) != 0) {
|
||||
#if defined(DEBUG)
|
||||
// When running with assertions enabled we do track the owner.
|
||||
|
@ -291,6 +295,8 @@ Monitor::~Monitor() {
|
|||
}
|
||||
|
||||
bool Monitor::TryEnter() {
|
||||
DEBUG_ASSERT(!ThreadInterruptScope::in_thread_interrupt_scope());
|
||||
|
||||
// Attempt to pass the semaphore but return immediately.
|
||||
if (TryAcquireSRWLockExclusive(&data_.lock_) != 0) {
|
||||
#if defined(DEBUG)
|
||||
|
@ -304,6 +310,8 @@ bool Monitor::TryEnter() {
|
|||
}
|
||||
|
||||
void Monitor::Enter() {
|
||||
DEBUG_ASSERT(!ThreadInterruptScope::in_thread_interrupt_scope());
|
||||
|
||||
AcquireSRWLockExclusive(&data_.lock_);
|
||||
|
||||
#if defined(DEBUG)
|
||||
|
|
|
@ -2,11 +2,12 @@
|
|||
// for details. All rights reserved. Use of this source code is governed by a
|
||||
// BSD-style license that can be found in the LICENSE file.
|
||||
|
||||
#include "vm/profiler.h"
|
||||
|
||||
#include "platform/address_sanitizer.h"
|
||||
#include "platform/atomic.h"
|
||||
#include "platform/memory_sanitizer.h"
|
||||
#include "platform/utils.h"
|
||||
|
||||
#include "platform/atomic.h"
|
||||
#include "vm/allocation.h"
|
||||
#include "vm/code_patcher.h"
|
||||
#if !defined(DART_PRECOMPILED_RUNTIME)
|
||||
|
@ -21,7 +22,6 @@
|
|||
#include "vm/native_symbol.h"
|
||||
#include "vm/object.h"
|
||||
#include "vm/os.h"
|
||||
#include "vm/profiler.h"
|
||||
#include "vm/profiler_service.h"
|
||||
#include "vm/reusable_handles.h"
|
||||
#include "vm/signal_handler.h"
|
||||
|
@ -610,10 +610,7 @@ class SampleBlockCleanupVisitor : public IsolateVisitor {
|
|||
|
||||
void VisitIsolate(Isolate* isolate) {
|
||||
isolate->set_current_allocation_sample_block(nullptr);
|
||||
{
|
||||
MutexLocker ml(isolate->current_sample_block_lock());
|
||||
isolate->set_current_sample_block(nullptr);
|
||||
}
|
||||
isolate->set_current_sample_block(nullptr);
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -700,8 +697,6 @@ SampleBlockBuffer::SampleBlockBuffer(intptr_t blocks,
|
|||
}
|
||||
capacity_ = blocks;
|
||||
cursor_ = 0;
|
||||
free_list_head_ = nullptr;
|
||||
free_list_tail_ = nullptr;
|
||||
}
|
||||
|
||||
SampleBlockBuffer::~SampleBlockBuffer() {
|
||||
|
@ -714,67 +709,34 @@ SampleBlockBuffer::~SampleBlockBuffer() {
|
|||
}
|
||||
|
||||
SampleBlock* SampleBlockBuffer::ReserveSampleBlock() {
|
||||
// Don't increment right away to avoid unlikely wrap-around errors.
|
||||
if (cursor_.load() < capacity_) {
|
||||
intptr_t index = cursor_.fetch_add(1u);
|
||||
// Check the index again to make sure the last block hasn't been snatched
|
||||
// from underneath us.
|
||||
if (index < capacity_) {
|
||||
return &blocks_[index];
|
||||
intptr_t capacity = capacity_;
|
||||
intptr_t start = cursor_.fetch_add(1) % capacity;
|
||||
intptr_t i = start;
|
||||
do {
|
||||
SampleBlock* block = &blocks_[i];
|
||||
if (block->TryAllocateFree()) {
|
||||
return block;
|
||||
}
|
||||
}
|
||||
// Try to re-use a previously freed SampleBlock once we've handed out each
|
||||
// block at least once. Freed blocks aren't cleared immediately and are still
|
||||
// valid until they're re-allocated, similar to how a ring buffer would clear
|
||||
// the oldest samples.
|
||||
SampleBlock* block = GetFreeBlock();
|
||||
if (block != nullptr) {
|
||||
block->Clear();
|
||||
}
|
||||
return block;
|
||||
}
|
||||
i = (i + 1) % capacity;
|
||||
} while (i != start);
|
||||
|
||||
void SampleBlockBuffer::ProcessCompletedBlocks() {
|
||||
Thread* thread = Thread::Current();
|
||||
DisableThreadInterruptsScope dtis(thread);
|
||||
int64_t start = Dart_TimelineGetMicros();
|
||||
thread->isolate()->ProcessFreeSampleBlocks(thread);
|
||||
int64_t end = Dart_TimelineGetMicros();
|
||||
Dart_TimelineEvent("SampleBlockBuffer::ProcessCompletedBlocks", start, end,
|
||||
Dart_Timeline_Event_Duration, 0, nullptr, nullptr);
|
||||
}
|
||||
|
||||
ProcessedSampleBuffer* SampleBlockListProcessor::BuildProcessedSampleBuffer(
|
||||
SampleFilter* filter,
|
||||
ProcessedSampleBuffer* buffer) {
|
||||
Thread* thread = Thread::Current();
|
||||
Zone* zone = thread->zone();
|
||||
|
||||
if (buffer == nullptr) {
|
||||
buffer = new (zone) ProcessedSampleBuffer();
|
||||
}
|
||||
while (head_ != nullptr) {
|
||||
head_->BuildProcessedSampleBuffer(filter, buffer);
|
||||
head_ = head_->next_free_;
|
||||
}
|
||||
return buffer;
|
||||
}
|
||||
|
||||
bool SampleBlockListProcessor::HasStreamableSamples(Thread* thread) {
|
||||
ReusableGrowableObjectArrayHandleScope reusable_array_handle_scope(thread);
|
||||
Zone* zone = thread->zone();
|
||||
Isolate* isolate = thread->isolate();
|
||||
ASSERT(isolate->tag_table() != GrowableObjectArray::null());
|
||||
GrowableObjectArray& tag_table = reusable_array_handle_scope.Handle();
|
||||
tag_table ^= isolate->tag_table();
|
||||
UserTag& tag = UserTag::Handle(zone);
|
||||
while (head_ != nullptr) {
|
||||
if (head_->HasStreamableSamples(tag_table, &tag)) {
|
||||
return true;
|
||||
// No free blocks: try for completed block instead.
|
||||
i = start;
|
||||
do {
|
||||
SampleBlock* block = &blocks_[i];
|
||||
if (block->TryAllocateCompleted()) {
|
||||
return block;
|
||||
}
|
||||
head_ = head_->next_free_;
|
||||
i = (i + 1) % capacity;
|
||||
} while (i != start);
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
void SampleBlockBuffer::FreeCompletedBlocks() {
|
||||
for (intptr_t i = 0; i < capacity_; i++) {
|
||||
blocks_[i].FreeCompleted();
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool SampleBlock::HasStreamableSamples(const GrowableObjectArray& tag_table,
|
||||
|
@ -792,6 +754,20 @@ bool SampleBlock::HasStreamableSamples(const GrowableObjectArray& tag_table,
|
|||
return false;
|
||||
}
|
||||
|
||||
static void FlushSampleBlocks(Isolate* isolate) {
|
||||
SampleBlock* block = isolate->current_sample_block();
|
||||
if (block != nullptr) {
|
||||
isolate->set_current_sample_block(nullptr);
|
||||
block->MarkCompleted();
|
||||
}
|
||||
|
||||
block = isolate->current_allocation_sample_block();
|
||||
if (block != nullptr) {
|
||||
isolate->set_current_allocation_sample_block(nullptr);
|
||||
block->MarkCompleted();
|
||||
}
|
||||
}
|
||||
|
||||
ProcessedSampleBuffer* SampleBlockBuffer::BuildProcessedSampleBuffer(
|
||||
SampleFilter* filter,
|
||||
ProcessedSampleBuffer* buffer) {
|
||||
|
@ -802,22 +778,29 @@ ProcessedSampleBuffer* SampleBlockBuffer::BuildProcessedSampleBuffer(
|
|||
buffer = new (zone) ProcessedSampleBuffer();
|
||||
}
|
||||
|
||||
FlushSampleBlocks(thread->isolate());
|
||||
|
||||
for (intptr_t i = 0; i < capacity_; ++i) {
|
||||
(&blocks_[i])->BuildProcessedSampleBuffer(filter, buffer);
|
||||
SampleBlock* block = &blocks_[i];
|
||||
if (block->TryAcquireStreaming(thread->isolate())) {
|
||||
block->BuildProcessedSampleBuffer(filter, buffer);
|
||||
if (filter->take_samples()) {
|
||||
block->StreamingToFree();
|
||||
} else {
|
||||
block->StreamingToCompleted();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return buffer;
|
||||
}
|
||||
|
||||
Sample* SampleBlock::ReserveSample() {
|
||||
if (full_.load()) {
|
||||
return nullptr;
|
||||
}
|
||||
intptr_t slot = cursor_.fetch_add(1u);
|
||||
if (slot + 1 == capacity_) {
|
||||
full_ = true;
|
||||
if (slot < capacity_) {
|
||||
return At(slot);
|
||||
}
|
||||
return (slot < capacity_) ? At(slot) : nullptr;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
Sample* SampleBlock::ReserveSampleAndLink(Sample* previous) {
|
||||
|
@ -858,34 +841,27 @@ Sample* SampleBlockBuffer::ReserveSampleImpl(Isolate* isolate,
|
|||
if (sample != nullptr) {
|
||||
return sample;
|
||||
}
|
||||
SampleBlock* next = nullptr;
|
||||
if (allocation_sample) {
|
||||
// We only need to be locked while accessing the CPU sample block since
|
||||
// Dart allocations can only occur on the mutator thread.
|
||||
next = ReserveSampleBlock();
|
||||
if (next == nullptr) {
|
||||
// We're out of blocks to reserve. Drop the sample.
|
||||
return nullptr;
|
||||
}
|
||||
isolate->set_current_allocation_sample_block(next);
|
||||
isolate->FreeSampleBlock(block);
|
||||
} else {
|
||||
MutexLocker locker(isolate->current_sample_block_lock());
|
||||
next = ReserveSampleBlock();
|
||||
if (next == nullptr) {
|
||||
// We're out of blocks to reserve. Drop the sample.
|
||||
return nullptr;
|
||||
}
|
||||
isolate->set_current_sample_block(next);
|
||||
isolate->FreeSampleBlock(block);
|
||||
}
|
||||
next->set_is_allocation_block(allocation_sample);
|
||||
|
||||
bool scheduled = can_process_block_.exchange(true);
|
||||
if (!scheduled) {
|
||||
isolate->mutator_thread()->ScheduleInterrupts(Thread::kVMInterrupt);
|
||||
SampleBlock* next = ReserveSampleBlock();
|
||||
if (next == nullptr) {
|
||||
// We're out of blocks to reserve. Drop the sample.
|
||||
return nullptr;
|
||||
}
|
||||
return ReserveSampleImpl(isolate, allocation_sample);
|
||||
|
||||
next->set_owner(isolate);
|
||||
if (allocation_sample) {
|
||||
isolate->set_current_allocation_sample_block(next);
|
||||
} else {
|
||||
isolate->set_current_sample_block(next);
|
||||
}
|
||||
if (block != nullptr) {
|
||||
block->MarkCompleted();
|
||||
if (!Isolate::IsSystemIsolate(isolate) &&
|
||||
isolate->TrySetHasCompletedBlocks()) {
|
||||
isolate->mutator_thread()->ScheduleInterrupts(Thread::kVMInterrupt);
|
||||
}
|
||||
}
|
||||
return next->ReserveSample();
|
||||
}
|
||||
|
||||
AllocationSampleBuffer::AllocationSampleBuffer(intptr_t capacity) {
|
||||
|
@ -2015,22 +1991,51 @@ void SampleBlockProcessor::Cleanup() {
|
|||
ASSERT(!thread_running_);
|
||||
}
|
||||
|
||||
class StreamableSampleFilter : public SampleFilter {
|
||||
public:
|
||||
explicit StreamableSampleFilter(Dart_Port port)
|
||||
: SampleFilter(port, kNoTaskFilter, -1, -1, true) {}
|
||||
|
||||
bool FilterSample(Sample* sample) override {
|
||||
const UserTag& tag =
|
||||
UserTag::Handle(UserTag::FindTagById(sample->user_tag()));
|
||||
return tag.streamable();
|
||||
}
|
||||
};
|
||||
|
||||
void Profiler::ProcessCompletedBlocks(Thread* thread) {
|
||||
if (!Service::profiler_stream.enabled()) return;
|
||||
Isolate* isolate = thread->isolate();
|
||||
if (Isolate::IsSystemIsolate(isolate)) return;
|
||||
|
||||
TIMELINE_DURATION(thread, Isolate, "Profiler::ProcessCompletedBlocks")
|
||||
DisableThreadInterruptsScope dtis(thread);
|
||||
StackZone zone(thread);
|
||||
HandleScope handle_scope(thread);
|
||||
StreamableSampleFilter filter(isolate->main_port());
|
||||
Profile profile;
|
||||
profile.Build(thread, &filter, Profiler::sample_block_buffer());
|
||||
ServiceEvent event(isolate, ServiceEvent::kCpuSamples);
|
||||
event.set_cpu_profile(&profile);
|
||||
Service::HandleEvent(&event);
|
||||
}
|
||||
|
||||
void Profiler::IsolateShutdown(Thread* thread) {
|
||||
FlushSampleBlocks(thread->isolate());
|
||||
ProcessCompletedBlocks(thread);
|
||||
}
|
||||
|
||||
class SampleBlockProcessorVisitor : public IsolateVisitor {
|
||||
public:
|
||||
SampleBlockProcessorVisitor() = default;
|
||||
virtual ~SampleBlockProcessorVisitor() = default;
|
||||
|
||||
void VisitIsolate(Isolate* isolate) {
|
||||
if (!isolate->should_process_blocks()) {
|
||||
return;
|
||||
if (isolate->TakeHasCompletedBlocks()) {
|
||||
Thread::EnterIsolateAsHelper(isolate, Thread::kSampleBlockTask);
|
||||
Profiler::ProcessCompletedBlocks(Thread::Current());
|
||||
Thread::ExitIsolateAsHelper();
|
||||
}
|
||||
Thread::EnterIsolateAsHelper(isolate, Thread::kSampleBlockTask);
|
||||
Thread* thread = Thread::Current();
|
||||
{
|
||||
DisableThreadInterruptsScope dtis(thread);
|
||||
isolate->ProcessFreeSampleBlocks(thread);
|
||||
}
|
||||
Thread::ExitIsolateAsHelper();
|
||||
}
|
||||
};
|
||||
|
||||
|
|
|
@ -93,8 +93,8 @@ class Profiler : public AllStatic {
|
|||
// SampleThread is called from inside the signal handler and hence it is very
|
||||
// critical that the implementation of SampleThread does not do any of the
|
||||
// following:
|
||||
// * Accessing TLS -- Because on Windows and Fuchsia the callback will be
|
||||
// running in a different thread.
|
||||
// * Accessing TLS -- Because on Fuchsia, Mac and Windows the callback will
|
||||
// be running in a different thread.
|
||||
// * Allocating memory -- Because this takes locks which may already be
|
||||
// held, resulting in a dead lock.
|
||||
// * Taking a lock -- See above.
|
||||
|
@ -106,6 +106,9 @@ class Profiler : public AllStatic {
|
|||
}
|
||||
inline static intptr_t Size();
|
||||
|
||||
static void ProcessCompletedBlocks(Thread* thread);
|
||||
static void IsolateShutdown(Thread* thread);
|
||||
|
||||
private:
|
||||
static void DumpStackTrace(uword sp, uword fp, uword pc, bool for_crash);
|
||||
|
||||
|
@ -157,11 +160,13 @@ class SampleFilter : public ValueObject {
|
|||
SampleFilter(Dart_Port port,
|
||||
intptr_t thread_task_mask,
|
||||
int64_t time_origin_micros,
|
||||
int64_t time_extent_micros)
|
||||
int64_t time_extent_micros,
|
||||
bool take_samples = false)
|
||||
: port_(port),
|
||||
thread_task_mask_(thread_task_mask),
|
||||
time_origin_micros_(time_origin_micros),
|
||||
time_extent_micros_(time_extent_micros) {
|
||||
time_extent_micros_(time_extent_micros),
|
||||
take_samples_(take_samples) {
|
||||
ASSERT(thread_task_mask != 0);
|
||||
ASSERT(time_origin_micros_ >= -1);
|
||||
ASSERT(time_extent_micros_ >= -1);
|
||||
|
@ -180,6 +185,8 @@ class SampleFilter : public ValueObject {
|
|||
// Returns |true| if |sample| passes the thread task filter.
|
||||
bool TaskFilterSample(Sample* sample);
|
||||
|
||||
bool take_samples() const { return take_samples_; }
|
||||
|
||||
static const intptr_t kNoTaskFilter = -1;
|
||||
|
||||
private:
|
||||
|
@ -187,6 +194,7 @@ class SampleFilter : public ValueObject {
|
|||
intptr_t thread_task_mask_;
|
||||
int64_t time_origin_micros_;
|
||||
int64_t time_extent_micros_;
|
||||
bool take_samples_;
|
||||
};
|
||||
|
||||
class ClearProfileVisitor : public SampleVisitor {
|
||||
|
@ -718,60 +726,88 @@ class SampleBlock : public SampleBuffer {
|
|||
SampleBlock() = default;
|
||||
virtual ~SampleBlock() = default;
|
||||
|
||||
void Clear() {
|
||||
allocation_block_ = false;
|
||||
cursor_ = 0;
|
||||
full_ = false;
|
||||
evictable_ = false;
|
||||
next_free_ = nullptr;
|
||||
}
|
||||
|
||||
// Returns the number of samples contained within this block.
|
||||
intptr_t capacity() const { return capacity_; }
|
||||
|
||||
// Specify whether or not this block is used for assigning allocation
|
||||
// samples.
|
||||
void set_is_allocation_block(bool is_allocation_block) {
|
||||
allocation_block_ = is_allocation_block;
|
||||
}
|
||||
|
||||
Isolate* owner() const { return owner_; }
|
||||
void set_owner(Isolate* isolate) { owner_ = isolate; }
|
||||
|
||||
// Manually marks the block as full so it can be processed and added back to
|
||||
// the pool of available blocks.
|
||||
void release_block() { full_.store(true); }
|
||||
|
||||
// When true, this sample block is considered complete and will no longer be
|
||||
// used to assign new Samples. This block is **not** available for
|
||||
// re-allocation simply because it's full. It must be processed by
|
||||
// SampleBlockBuffer::ProcessCompletedBlocks before it can be considered
|
||||
// evictable and available for re-allocation.
|
||||
bool is_full() const { return full_.load(); }
|
||||
|
||||
// When true, this sample block is available for re-allocation.
|
||||
bool evictable() const { return evictable_.load(); }
|
||||
|
||||
virtual Sample* ReserveSample();
|
||||
virtual Sample* ReserveSampleAndLink(Sample* previous);
|
||||
|
||||
bool TryAllocateFree() {
|
||||
State expected = kFree;
|
||||
State desired = kSampling;
|
||||
std::memory_order success_order = std::memory_order_acquire;
|
||||
std::memory_order failure_order = std::memory_order_relaxed;
|
||||
return state_.compare_exchange_strong(expected, desired, success_order,
|
||||
failure_order);
|
||||
}
|
||||
bool TryAllocateCompleted() {
|
||||
State expected = kCompleted;
|
||||
State desired = kSampling;
|
||||
std::memory_order success_order = std::memory_order_acquire;
|
||||
std::memory_order failure_order = std::memory_order_relaxed;
|
||||
if (state_.compare_exchange_strong(expected, desired, success_order,
|
||||
failure_order)) {
|
||||
owner_ = nullptr;
|
||||
cursor_ = 0;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
void MarkCompleted() {
|
||||
ASSERT(state_.load(std::memory_order_relaxed) == kSampling);
|
||||
state_.store(kCompleted, std::memory_order_release);
|
||||
}
|
||||
bool TryAcquireStreaming(Isolate* isolate) {
|
||||
if (state_.load(std::memory_order_relaxed) != kCompleted) return false;
|
||||
if (owner_ != isolate) return false;
|
||||
|
||||
State expected = kCompleted;
|
||||
State desired = kStreaming;
|
||||
std::memory_order success_order = std::memory_order_acquire;
|
||||
std::memory_order failure_order = std::memory_order_relaxed;
|
||||
return state_.compare_exchange_strong(expected, desired, success_order,
|
||||
failure_order);
|
||||
}
|
||||
void StreamingToCompleted() {
|
||||
ASSERT(state_.load(std::memory_order_relaxed) == kStreaming);
|
||||
state_.store(kCompleted, std::memory_order_relaxed);
|
||||
}
|
||||
void StreamingToFree() {
|
||||
ASSERT(state_.load(std::memory_order_relaxed) == kStreaming);
|
||||
owner_ = nullptr;
|
||||
cursor_ = 0;
|
||||
state_.store(kFree, std::memory_order_release);
|
||||
}
|
||||
void FreeCompleted() {
|
||||
State expected = kCompleted;
|
||||
State desired = kStreaming;
|
||||
std::memory_order success_order = std::memory_order_acquire;
|
||||
std::memory_order failure_order = std::memory_order_relaxed;
|
||||
if (state_.compare_exchange_strong(expected, desired, success_order,
|
||||
failure_order)) {
|
||||
StreamingToFree();
|
||||
}
|
||||
}
|
||||
|
||||
protected:
|
||||
bool HasStreamableSamples(const GrowableObjectArray& tag_table, UserTag* tag);
|
||||
|
||||
enum State : uint32_t {
|
||||
kFree,
|
||||
kSampling, // I.e., writing.
|
||||
kCompleted,
|
||||
kStreaming, // I.e., reading.
|
||||
};
|
||||
std::atomic<State> state_ = kFree;
|
||||
RelaxedAtomic<uint32_t> cursor_ = 0;
|
||||
Isolate* owner_ = nullptr;
|
||||
bool allocation_block_ = false;
|
||||
|
||||
intptr_t index_;
|
||||
RelaxedAtomic<int> cursor_ = 0;
|
||||
RelaxedAtomic<bool> full_ = false;
|
||||
RelaxedAtomic<bool> evictable_ = false;
|
||||
|
||||
SampleBlock* next_free_ = nullptr;
|
||||
|
||||
private:
|
||||
friend class SampleBlockListProcessor;
|
||||
friend class SampleBlockBuffer;
|
||||
friend class Isolate;
|
||||
|
||||
DISALLOW_COPY_AND_ASSIGN(SampleBlock);
|
||||
};
|
||||
|
@ -792,23 +828,12 @@ class SampleBlockBuffer : public ProcessedSampleBufferBuilder {
|
|||
|
||||
void VisitSamples(SampleVisitor* visitor) {
|
||||
ASSERT(visitor != NULL);
|
||||
for (intptr_t i = 0; i < cursor_.load(); ++i) {
|
||||
(&blocks_[i])->VisitSamples(visitor);
|
||||
for (intptr_t i = 0; i < capacity_; ++i) {
|
||||
blocks_[i].VisitSamples(visitor);
|
||||
}
|
||||
}
|
||||
|
||||
// Returns true when there is at least a single block that needs to be
|
||||
// processed.
|
||||
//
|
||||
// NOTE: this should only be called from the interrupt handler as
|
||||
// invocation will have the side effect of clearing the underlying flag.
|
||||
bool process_blocks() { return can_process_block_.exchange(false); }
|
||||
|
||||
// Iterates over the blocks in the buffer and processes blocks marked as
|
||||
// full. Processing consists of sending a service event with the samples from
|
||||
// completed, unprocessed blocks and marking these blocks are evictable
|
||||
// (i.e., safe to be re-allocated and re-used).
|
||||
void ProcessCompletedBlocks();
|
||||
void FreeCompletedBlocks();
|
||||
|
||||
// Reserves a sample for a CPU profile.
|
||||
//
|
||||
|
@ -832,41 +857,10 @@ class SampleBlockBuffer : public ProcessedSampleBufferBuilder {
|
|||
// Returns nullptr if there are no available blocks.
|
||||
SampleBlock* ReserveSampleBlock();
|
||||
|
||||
void FreeBlock(SampleBlock* block) {
|
||||
ASSERT(block->next_free_ == nullptr);
|
||||
MutexLocker ml(&free_block_lock_);
|
||||
if (free_list_head_ == nullptr) {
|
||||
free_list_head_ = block;
|
||||
free_list_tail_ = block;
|
||||
return;
|
||||
}
|
||||
free_list_tail_->next_free_ = block;
|
||||
free_list_tail_ = block;
|
||||
}
|
||||
|
||||
SampleBlock* GetFreeBlock() {
|
||||
MutexLocker ml(&free_block_lock_);
|
||||
if (free_list_head_ == nullptr) {
|
||||
return nullptr;
|
||||
}
|
||||
SampleBlock* block = free_list_head_;
|
||||
free_list_head_ = block->next_free_;
|
||||
if (free_list_head_ == nullptr) {
|
||||
free_list_tail_ = nullptr;
|
||||
}
|
||||
block->next_free_ = nullptr;
|
||||
return block;
|
||||
}
|
||||
|
||||
Mutex free_block_lock_;
|
||||
RelaxedAtomic<bool> can_process_block_ = false;
|
||||
|
||||
// Sample block management.
|
||||
RelaxedAtomic<int> cursor_;
|
||||
SampleBlock* blocks_;
|
||||
intptr_t capacity_;
|
||||
SampleBlock* free_list_head_;
|
||||
SampleBlock* free_list_tail_;
|
||||
|
||||
// Sample buffer management.
|
||||
VirtualMemory* memory_;
|
||||
|
@ -876,9 +870,9 @@ class SampleBlockBuffer : public ProcessedSampleBufferBuilder {
|
|||
DISALLOW_COPY_AND_ASSIGN(SampleBlockBuffer);
|
||||
};
|
||||
|
||||
class SampleBlockListProcessor : public ProcessedSampleBufferBuilder {
|
||||
class StreamingSampleBufferBuilder : public ProcessedSampleBufferBuilder {
|
||||
public:
|
||||
explicit SampleBlockListProcessor(SampleBlock* head) : head_(head) {}
|
||||
explicit StreamingSampleBufferBuilder(Isolate* isolate) : isolate_(isolate) {}
|
||||
|
||||
virtual ProcessedSampleBuffer* BuildProcessedSampleBuffer(
|
||||
SampleFilter* filter,
|
||||
|
@ -889,9 +883,9 @@ class SampleBlockListProcessor : public ProcessedSampleBufferBuilder {
|
|||
bool HasStreamableSamples(Thread* thread);
|
||||
|
||||
private:
|
||||
SampleBlock* head_;
|
||||
Isolate* isolate_;
|
||||
|
||||
DISALLOW_COPY_AND_ASSIGN(SampleBlockListProcessor);
|
||||
DISALLOW_COPY_AND_ASSIGN(StreamingSampleBufferBuilder);
|
||||
};
|
||||
|
||||
class AllocationSampleBuffer : public SampleBuffer {
|
||||
|
|
|
@ -1486,7 +1486,6 @@ void Profile::Build(Thread* thread,
|
|||
ProcessedSampleBufferBuilder* sample_buffer) {
|
||||
// Disable thread interrupts while processing the buffer.
|
||||
DisableThreadInterruptsScope dtis(thread);
|
||||
ThreadInterrupter::SampleBufferReaderScope scope;
|
||||
ProfileBuilder builder(thread, filter, sample_buffer, this);
|
||||
builder.Build();
|
||||
}
|
||||
|
@ -1906,7 +1905,6 @@ void ProfilerService::ClearSamples() {
|
|||
|
||||
// Disable thread interrupts while processing the buffer.
|
||||
DisableThreadInterruptsScope dtis(thread);
|
||||
ThreadInterrupter::SampleBufferReaderScope scope;
|
||||
|
||||
ClearProfileVisitor clear_profile(isolate);
|
||||
sample_block_buffer->VisitSamples(&clear_profile);
|
||||
|
|
|
@ -80,9 +80,7 @@ class ProfileSampleBufferTestHelper : public SampleVisitor {
|
|||
intptr_t sum_ = 0;
|
||||
};
|
||||
|
||||
void VisitSamples(SampleBlockBuffer* buffer, SampleVisitor* visitor) {
|
||||
// Mark the completed blocks as free so they can be re-used.
|
||||
buffer->ProcessCompletedBlocks();
|
||||
static void VisitSamples(SampleBlockBuffer* buffer, SampleVisitor* visitor) {
|
||||
visitor->Reset();
|
||||
buffer->VisitSamples(visitor);
|
||||
}
|
||||
|
@ -119,35 +117,38 @@ TEST_CASE(Profiler_SampleBufferWrapTest) {
|
|||
Sample* s;
|
||||
|
||||
s = sample_buffer->ReserveCPUSample(isolate);
|
||||
EXPECT_NOTNULL(s);
|
||||
s->Init(i, kValidTimeStamp, 0);
|
||||
s->SetAt(0, 2);
|
||||
VisitSamples(sample_buffer, &visitor);
|
||||
EXPECT_EQ(2, visitor.sum());
|
||||
|
||||
s = sample_buffer->ReserveCPUSample(isolate);
|
||||
EXPECT_NOTNULL(s);
|
||||
s->Init(i, kValidTimeStamp, 0);
|
||||
s->SetAt(0, 4);
|
||||
VisitSamples(sample_buffer, &visitor);
|
||||
EXPECT_EQ(6, visitor.sum());
|
||||
|
||||
s = sample_buffer->ReserveCPUSample(isolate);
|
||||
EXPECT_NOTNULL(s);
|
||||
s->Init(i, kValidTimeStamp, 0);
|
||||
s->SetAt(0, 6);
|
||||
VisitSamples(sample_buffer, &visitor);
|
||||
EXPECT_EQ(12, visitor.sum());
|
||||
|
||||
// Mark the completed blocks as free so they can be re-used.
|
||||
sample_buffer->ProcessCompletedBlocks();
|
||||
sample_buffer->FreeCompletedBlocks();
|
||||
|
||||
s = sample_buffer->ReserveCPUSample(isolate);
|
||||
EXPECT_NOTNULL(s);
|
||||
s->Init(i, kValidTimeStamp, 0);
|
||||
s->SetAt(0, 8);
|
||||
VisitSamples(sample_buffer, &visitor);
|
||||
EXPECT_EQ(18, visitor.sum());
|
||||
{
|
||||
MutexLocker ml(isolate->current_sample_block_lock());
|
||||
isolate->set_current_sample_block(nullptr);
|
||||
}
|
||||
|
||||
// The overridden sample buffer will be freed before isolate shutdown.
|
||||
isolate->set_current_sample_block(nullptr);
|
||||
}
|
||||
|
||||
TEST_CASE(Profiler_SampleBufferIterateTest) {
|
||||
|
@ -163,33 +164,35 @@ TEST_CASE(Profiler_SampleBufferIterateTest) {
|
|||
EXPECT_EQ(0, visitor.visited());
|
||||
Sample* s;
|
||||
s = sample_buffer->ReserveCPUSample(isolate);
|
||||
EXPECT_NOTNULL(s);
|
||||
s->Init(i, kValidTimeStamp, 0);
|
||||
s->SetAt(0, kValidPc);
|
||||
VisitSamples(sample_buffer, &visitor);
|
||||
EXPECT_EQ(1, visitor.visited());
|
||||
|
||||
s = sample_buffer->ReserveCPUSample(isolate);
|
||||
EXPECT_NOTNULL(s);
|
||||
s->Init(i, kValidTimeStamp, 0);
|
||||
s->SetAt(0, kValidPc);
|
||||
VisitSamples(sample_buffer, &visitor);
|
||||
EXPECT_EQ(2, visitor.visited());
|
||||
|
||||
s = sample_buffer->ReserveCPUSample(isolate);
|
||||
EXPECT_NOTNULL(s);
|
||||
s->Init(i, kValidTimeStamp, 0);
|
||||
s->SetAt(0, kValidPc);
|
||||
VisitSamples(sample_buffer, &visitor);
|
||||
EXPECT_EQ(3, visitor.visited());
|
||||
|
||||
s = sample_buffer->ReserveCPUSample(isolate);
|
||||
EXPECT_NOTNULL(s);
|
||||
s->Init(i, kValidTimeStamp, 0);
|
||||
s->SetAt(0, kValidPc);
|
||||
VisitSamples(sample_buffer, &visitor);
|
||||
EXPECT_EQ(3, visitor.visited());
|
||||
|
||||
{
|
||||
MutexLocker ml(isolate->current_sample_block_lock());
|
||||
isolate->set_current_sample_block(nullptr);
|
||||
}
|
||||
// The overridden sample buffer will be freed before isolate shutdown.
|
||||
isolate->set_current_sample_block(nullptr);
|
||||
}
|
||||
|
||||
TEST_CASE(Profiler_AllocationSampleTest) {
|
||||
|
|
|
@ -451,15 +451,8 @@ ErrorPtr Thread::HandleInterrupts() {
|
|||
}
|
||||
|
||||
#if !defined(PRODUCT)
|
||||
// Don't block system isolates to process CPU samples to avoid blocking
|
||||
// them during critical tasks (e.g., initial compilation).
|
||||
if (!Isolate::IsSystemIsolate(isolate())) {
|
||||
// Processes completed SampleBlocks and sends CPU sample events over the
|
||||
// service protocol when applicable.
|
||||
SampleBlockBuffer* sample_buffer = Profiler::sample_block_buffer();
|
||||
if (sample_buffer != nullptr && sample_buffer->process_blocks()) {
|
||||
sample_buffer->ProcessCompletedBlocks();
|
||||
}
|
||||
if (isolate()->TakeHasCompletedBlocks()) {
|
||||
Profiler::ProcessCompletedBlocks(this);
|
||||
}
|
||||
HeapProfileSampler& sampler = heap_sampler();
|
||||
if (sampler.ShouldSetThreadSamplingInterval()) {
|
||||
|
|
|
@ -48,11 +48,6 @@ ThreadJoinId ThreadInterrupter::interrupter_thread_id_ =
|
|||
Monitor* ThreadInterrupter::monitor_ = NULL;
|
||||
intptr_t ThreadInterrupter::interrupt_period_ = 1000;
|
||||
intptr_t ThreadInterrupter::current_wait_time_ = Monitor::kNoTimeout;
|
||||
// Note this initial state means there is one sample buffer reader. This
|
||||
// allows the EnterSampleReader during Cleanup (needed to ensure the buffer can
|
||||
// be safely freed) to be balanced by a ExitSampleReader during Init.
|
||||
std::atomic<intptr_t> ThreadInterrupter::sample_buffer_lock_ = {-1};
|
||||
std::atomic<intptr_t> ThreadInterrupter::sample_buffer_waiters_ = {1};
|
||||
|
||||
void ThreadInterrupter::Init() {
|
||||
ASSERT(!initialized_);
|
||||
|
@ -81,8 +76,6 @@ void ThreadInterrupter::Startup() {
|
|||
if (FLAG_trace_thread_interrupter) {
|
||||
OS::PrintErr("ThreadInterrupter running.\n");
|
||||
}
|
||||
|
||||
ExitSampleReader();
|
||||
}
|
||||
|
||||
void ThreadInterrupter::Cleanup() {
|
||||
|
@ -110,9 +103,6 @@ void ThreadInterrupter::Cleanup() {
|
|||
if (FLAG_trace_thread_interrupter) {
|
||||
OS::PrintErr("ThreadInterrupter shut down.\n");
|
||||
}
|
||||
|
||||
// Wait for outstanding signals.
|
||||
EnterSampleReader();
|
||||
}
|
||||
|
||||
// Delay between interrupts.
|
||||
|
|
|
@ -36,52 +36,6 @@ class ThreadInterrupter : public AllStatic {
|
|||
// Interrupt a thread.
|
||||
static void InterruptThread(OSThread* thread);
|
||||
|
||||
class SampleBufferWriterScope : public ValueObject {
|
||||
public:
|
||||
SampleBufferWriterScope() {
|
||||
intptr_t old_value = sample_buffer_lock_.load(std::memory_order_relaxed);
|
||||
intptr_t new_value;
|
||||
do {
|
||||
if (old_value < 0) {
|
||||
entered_lock_ = false;
|
||||
return;
|
||||
}
|
||||
new_value = old_value + 1;
|
||||
} while (!sample_buffer_lock_.compare_exchange_weak(
|
||||
old_value, new_value, std::memory_order_acquire));
|
||||
entered_lock_ = true;
|
||||
}
|
||||
|
||||
~SampleBufferWriterScope() {
|
||||
if (!entered_lock_) return;
|
||||
intptr_t old_value = sample_buffer_lock_.load(std::memory_order_relaxed);
|
||||
intptr_t new_value;
|
||||
do {
|
||||
ASSERT(old_value > 0);
|
||||
new_value = old_value - 1;
|
||||
} while (!sample_buffer_lock_.compare_exchange_weak(
|
||||
old_value, new_value, std::memory_order_release));
|
||||
}
|
||||
|
||||
bool CanSample() const {
|
||||
return entered_lock_ &&
|
||||
sample_buffer_waiters_.load(std::memory_order_relaxed) == 0;
|
||||
}
|
||||
|
||||
private:
|
||||
bool entered_lock_;
|
||||
DISALLOW_COPY_AND_ASSIGN(SampleBufferWriterScope);
|
||||
};
|
||||
|
||||
class SampleBufferReaderScope : public ValueObject {
|
||||
public:
|
||||
SampleBufferReaderScope() { EnterSampleReader(); }
|
||||
~SampleBufferReaderScope() { ExitSampleReader(); }
|
||||
|
||||
private:
|
||||
DISALLOW_COPY_AND_ASSIGN(SampleBufferReaderScope);
|
||||
};
|
||||
|
||||
private:
|
||||
static const intptr_t kMaxThreads = 4096;
|
||||
static bool initialized_;
|
||||
|
@ -93,15 +47,6 @@ class ThreadInterrupter : public AllStatic {
|
|||
static intptr_t interrupt_period_;
|
||||
static intptr_t current_wait_time_;
|
||||
|
||||
// Something like a reader-writer lock. Positive values indicate there are
|
||||
// outstanding signal handlers that can write to the sample buffer. Negative
|
||||
// values indicate there are outstanding sample buffer processors that can
|
||||
// read from the sample buffer. A reader will spin-wait to enter the lock. A
|
||||
// writer will give up if it fails to enter lock, causing samples to be
|
||||
// skipping while we are processing the sample buffer or trying to shut down.
|
||||
static std::atomic<intptr_t> sample_buffer_lock_;
|
||||
static std::atomic<intptr_t> sample_buffer_waiters_;
|
||||
|
||||
static bool InDeepSleep() {
|
||||
return current_wait_time_ == Monitor::kNoTimeout;
|
||||
}
|
||||
|
@ -112,33 +57,6 @@ class ThreadInterrupter : public AllStatic {
|
|||
|
||||
static void RemoveSignalHandler();
|
||||
|
||||
static void EnterSampleReader() {
|
||||
sample_buffer_waiters_.fetch_add(1, std::memory_order_relaxed);
|
||||
|
||||
intptr_t old_value = sample_buffer_lock_.load(std::memory_order_relaxed);
|
||||
intptr_t new_value;
|
||||
do {
|
||||
while (old_value > 0) {
|
||||
// Spin waiting for outstanding SIGPROFs to complete.
|
||||
old_value = sample_buffer_lock_.load(std::memory_order_relaxed);
|
||||
}
|
||||
new_value = old_value - 1;
|
||||
} while (!sample_buffer_lock_.compare_exchange_weak(
|
||||
old_value, new_value, std::memory_order_acquire));
|
||||
}
|
||||
|
||||
static void ExitSampleReader() {
|
||||
sample_buffer_waiters_.fetch_sub(1, std::memory_order_relaxed);
|
||||
|
||||
intptr_t old_value = sample_buffer_lock_.load(std::memory_order_relaxed);
|
||||
intptr_t new_value;
|
||||
do {
|
||||
ASSERT(old_value < 0);
|
||||
new_value = old_value + 1;
|
||||
} while (!sample_buffer_lock_.compare_exchange_weak(
|
||||
old_value, new_value, std::memory_order_release));
|
||||
}
|
||||
|
||||
friend class ThreadInterrupterVisitIsolates;
|
||||
};
|
||||
|
||||
|
|
|
@ -41,10 +41,7 @@ void ThreadInterruptSignalHandler(int signal, siginfo_t* info, void* context_) {
|
|||
if (thread == NULL) {
|
||||
return;
|
||||
}
|
||||
ThreadInterrupter::SampleBufferWriterScope scope;
|
||||
if (!scope.CanSample()) {
|
||||
return;
|
||||
}
|
||||
ThreadInterruptScope signal_handler_scope;
|
||||
// Extract thread state.
|
||||
ucontext_t* context = reinterpret_cast<ucontext_t*>(context_);
|
||||
mcontext_t mcontext = context->uc_mcontext;
|
||||
|
|
|
@ -161,6 +161,7 @@ class ThreadInterrupterFuchsia : public AllStatic {
|
|||
// here as the thread which is being queried is suspended.
|
||||
Thread* thread = static_cast<Thread*>(os_thread->thread());
|
||||
if (thread != NULL) {
|
||||
ThreadInterruptScope signal_handler_scope;
|
||||
Profiler::SampleThread(thread, its);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -31,10 +31,7 @@ class ThreadInterrupterLinux : public AllStatic {
|
|||
if (thread == NULL) {
|
||||
return;
|
||||
}
|
||||
ThreadInterrupter::SampleBufferWriterScope scope;
|
||||
if (!scope.CanSample()) {
|
||||
return;
|
||||
}
|
||||
ThreadInterruptScope signal_handler_scope;
|
||||
// Extract thread state.
|
||||
ucontext_t* context = reinterpret_cast<ucontext_t*>(context_);
|
||||
mcontext_t mcontext = context->uc_mcontext;
|
||||
|
|
|
@ -66,6 +66,7 @@ class ThreadInterrupterMacOS {
|
|||
if (thread == nullptr) {
|
||||
return;
|
||||
}
|
||||
ThreadInterruptScope signal_handler_scope;
|
||||
Profiler::SampleThread(thread, ProcessState(state));
|
||||
}
|
||||
|
||||
|
@ -117,10 +118,6 @@ void ThreadInterrupter::InterruptThread(OSThread* os_thread) {
|
|||
OS::PrintErr("ThreadInterrupter interrupting %p\n", os_thread->id());
|
||||
}
|
||||
|
||||
ThreadInterrupter::SampleBufferWriterScope scope;
|
||||
if (!scope.CanSample()) {
|
||||
return;
|
||||
}
|
||||
ThreadInterrupterMacOS interrupter(os_thread);
|
||||
interrupter.CollectSample();
|
||||
}
|
||||
|
|
|
@ -94,6 +94,7 @@ class ThreadInterrupterWin : public AllStatic {
|
|||
// here as the thread which is being queried is suspended.
|
||||
Thread* thread = static_cast<Thread*>(os_thread->thread());
|
||||
if (thread != NULL) {
|
||||
ThreadInterruptScope signal_handler_scope;
|
||||
Profiler::SampleThread(thread, its);
|
||||
}
|
||||
ResumeThread(handle);
|
||||
|
|
Loading…
Reference in a new issue