[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:
Ryan Macnak 2023-02-21 19:07:57 +00:00 committed by Commit Queue
parent f56c45eb37
commit 347c49354e
22 changed files with 419 additions and 569 deletions

View file

@ -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

View file

@ -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
}

View file

@ -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*>(&current_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_;

View file

@ -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) {

View file

@ -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_

View file

@ -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);

View file

@ -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);

View file

@ -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);

View file

@ -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);

View file

@ -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)

View file

@ -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();
}
};

View file

@ -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 {

View file

@ -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);

View file

@ -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) {

View file

@ -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()) {

View file

@ -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.

View file

@ -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;
};

View file

@ -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;

View file

@ -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);
}
}

View file

@ -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;

View file

@ -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();
}

View file

@ -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);