59
59
ProcessToProfileData ,
60
60
ProfileData ,
61
61
StackToSampleCount ,
62
+ comma_separated_enum_list ,
62
63
integer_range ,
63
64
positive_integer ,
64
65
)
@@ -112,9 +113,6 @@ def needs_musl_ap_cached(process: Process) -> bool:
112
113
return is_musl (process , maps ) and not any ("glibc-compat" in m .path for m in maps )
113
114
114
115
115
- JAVA_SAFEMODE_ALL = "all" # magic value for *all* options from JavaSafemodeOptions
116
-
117
-
118
116
class JavaSafemodeOptions (str , Enum ):
119
117
# a profiled process was OOM-killed and we saw it in the kernel log
120
118
PROFILED_OOM = "profiled-oom"
@@ -138,18 +136,45 @@ class JavaSafemodeOptions(str, Enum):
138
136
AP_LOADED_CHECK = "ap-loaded-check"
139
137
140
138
139
+ JAVA_SAFEMODE_ALL = "all" # magic value for *all* options from JavaSafemodeOptions
141
140
JAVA_SAFEMODE_ALL_OPTIONS = [o .value for o in JavaSafemodeOptions ]
142
141
JAVA_SAFEMODE_DEFAULT_OPTIONS = [
143
142
JavaSafemodeOptions .PROFILED_OOM .value ,
144
143
JavaSafemodeOptions .PROFILED_SIGNALED .value ,
145
144
JavaSafemodeOptions .HSERR .value ,
146
145
]
147
146
148
- # https://github.com/jvm-profiling-tools/async-profiler/blob/63799a6055363cbd7ca8ef951e2393db0d0ba7dd/src/profiler.cpp#L77
149
- JAVA_ASYNC_PROFILER_DEFAULT_SAFEMODE = 256 # StackRecovery.PROBE_SP
150
147
151
148
SUPPORTED_AP_MODES = ["cpu" , "itimer" , "alloc" ]
152
149
150
+
151
+ # see StackWalkFeatures
152
+ # https://github.com/async-profiler/async-profiler/blob/a17529378b47e6700d84f89d74ca5e6284ffd1a6/src/arguments.h#L95-L112
153
+ class AsyncProfilerFeatures (str , Enum ):
154
+ # these will be controllable via "features" in a future AP release:
155
+ #
156
+ # unknown_java
157
+ # unwind_stub
158
+ # unwind_comp
159
+ # unwind_native
160
+ # java_anchor
161
+ # gc_traces
162
+
163
+ # these are controllable via "features" in AP 3.0
164
+ probe_sp = "probesp"
165
+ vtable_target = "vtable"
166
+ comp_task = "comptask"
167
+ # as of AP 3.0
168
+
169
+
170
+ SUPPORTED_AP_FEATURES = [o .value for o in AsyncProfilerFeatures ]
171
+ DEFAULT_AP_FEATURES = [AsyncProfilerFeatures .probe_sp .value , AsyncProfilerFeatures .vtable_target .value ]
172
+
173
+ # see options still here and not in "features":
174
+ # https://github.com/async-profiler/async-profiler/blob/a17529378b47e6700d84f89d74ca5e6284ffd1a6/src/arguments.cpp#L262
175
+ # we don't want any of them disabled by default.
176
+ JAVA_ASYNC_PROFILER_DEFAULT_SAFEMODE = 0
177
+
153
178
PROBLEMATIC_FRAME_REGEX = re .compile (r"^# Problematic frame:\n# (.*?)\n#\n" , re .MULTILINE | re .DOTALL )
154
179
"""
155
180
See VMError::report.
@@ -239,7 +264,7 @@ def __init__(self, stop_event: Event, jattach_timeout: int):
239
264
def run (self , process : Process , cmd : str ) -> str :
240
265
try :
241
266
return run_process (
242
- [asprof_path (), "jcmd" , "--jattach-cmd" , cmd , str (process .pid )],
267
+ [asprof_path (), "jcmd" , str (process .pid ), cmd ],
243
268
stop_event = self .stop_event ,
244
269
timeout = self .jattach_timeout ,
245
270
).stdout .decode ()
@@ -467,6 +492,7 @@ def __init__(
467
492
profiler_state : ProfilerState ,
468
493
mode : str ,
469
494
ap_safemode : int ,
495
+ ap_features : List [str ],
470
496
ap_args : str ,
471
497
jattach_timeout : int = _DEFAULT_JATTACH_TIMEOUT ,
472
498
mcache : int = 0 ,
@@ -517,6 +543,7 @@ def __init__(
517
543
self ._mode = mode
518
544
self ._fdtransfer_path = f"@async-profiler-{ process .pid } -{ secrets .token_hex (10 )} " if mode == "cpu" else None
519
545
self ._ap_safemode = ap_safemode
546
+ self ._ap_features = ap_features
520
547
self ._ap_args = ap_args
521
548
self ._jattach_timeout = jattach_timeout
522
549
self ._mcache = mcache
@@ -651,10 +678,10 @@ def _check_disk_requirements(self) -> None:
651
678
def _get_base_cmd (self ) -> List [str ]:
652
679
return [
653
680
asprof_path (),
654
- "jattach" ,
655
- "-L " ,
681
+ str ( self . process . pid ) ,
682
+ "load " ,
656
683
self ._libap_path_process ,
657
- "--jattach-cmd" ,
684
+ "true" , # 'true' means the given path ^^ is absolute.
658
685
]
659
686
660
687
def _get_extra_ap_args (self ) -> str :
@@ -677,7 +704,9 @@ def _get_start_cmd(self, interval: int, ap_timeout: int) -> List[str]:
677
704
f"{ self ._get_ap_output_args ()} { self ._get_interval_arg (interval )} ,"
678
705
f"log={ self ._log_path_process } "
679
706
f"{ f',fdtransfer={ self ._fdtransfer_path } ' if self ._mode == 'cpu' else '' } "
680
- f",safemode={ self ._ap_safemode } ,timeout={ ap_timeout } "
707
+ f",safemode={ self ._ap_safemode } ,"
708
+ f",features={ '+' .join (self ._ap_features )} ," # asprof uses '+' as a separator: https://github.com/async-profiler/async-profiler/blob/a17529378b47e6700d84f89d74ca5e6284ffd1a6/src/launcher/main.cpp#L441 # noqa
709
+ f"timeout={ ap_timeout } "
681
710
f"{ ',lib' if self ._profiler_state .insert_dso_name else '' } { self ._get_extra_ap_args ()} "
682
711
]
683
712
@@ -705,7 +734,7 @@ def _run_async_profiler(self, cmd: List[str]) -> str:
705
734
try :
706
735
# kill jattach with SIGTERM if it hangs. it will go down
707
736
run_process (
708
- cmd + [ str ( self . process . pid )] ,
737
+ cmd ,
709
738
stop_event = self ._profiler_state .stop_event ,
710
739
timeout = self ._jattach_timeout ,
711
740
kill_signal = signal .SIGTERM ,
@@ -773,7 +802,10 @@ def start_async_profiler(self, interval: int, second_try: bool = False, ap_timeo
773
802
if e .is_ap_loaded :
774
803
if (
775
804
e .returncode == 200 # 200 == AP's COMMAND_ERROR
776
- and e .get_ap_log () == "[ERROR] Profiler already started\n "
805
+ # this is the error we get when we try to start AP on a process that already has it loaded.
806
+ # check with "in" and not "==" in case other warnings/infos are printed alongside it,
807
+ # but generally, we expect it to be the only output in this case.
808
+ and "[ERROR] Profiler already started\n " in e .get_ap_log ()
777
809
):
778
810
# profiler was already running
779
811
return False
@@ -817,11 +849,22 @@ def read_output(self) -> Optional[str]:
817
849
"--java-async-profiler-safemode" ,
818
850
dest = "java_async_profiler_safemode" ,
819
851
default = JAVA_ASYNC_PROFILER_DEFAULT_SAFEMODE ,
820
- type = integer_range (0 , 0x200 ),
821
- metavar = "[0-511 ]" ,
852
+ type = integer_range (0 , 0x40 ),
853
+ metavar = "[0-63 ]" ,
822
854
help = "Controls the 'safemode' parameter passed to async-profiler. This is parameter denotes multiple"
823
- " bits that describe different stack recovery techniques which async-profiler uses (see StackRecovery"
824
- " enum in async-profiler's code, in profiler.cpp)."
855
+ " bits that describe different stack recovery techniques which async-profiler uses. In a future release,"
856
+ " these optinos will be migrated to the 'features' parameter."
857
+ " Defaults to '%(default)s'." ,
858
+ ),
859
+ ProfilerArgument (
860
+ "--java-async-profiler-features" ,
861
+ dest = "java_async_profiler_features" ,
862
+ default = DEFAULT_AP_FEATURES ,
863
+ metavar = "," .join (SUPPORTED_AP_FEATURES ),
864
+ type = functools .partial (comma_separated_enum_list , SUPPORTED_AP_FEATURES ),
865
+ help = "Controls the 'features' parameter passed to async-profiler. This is parameter is a comma-separated"
866
+ " list of options which describe async-profiler's available features (see StackWalkFeatures"
867
+ " enum in async-profiler's code, in arguments.h)."
825
868
" Defaults to '%(default)s')." ,
826
869
),
827
870
ProfilerArgument (
@@ -933,6 +976,7 @@ def __init__(
933
976
java_version_check : bool ,
934
977
java_async_profiler_mode : str ,
935
978
java_async_profiler_safemode : int ,
979
+ java_async_profiler_features : List [str ],
936
980
java_async_profiler_args : str ,
937
981
java_safemode : str ,
938
982
java_jattach_timeout : int ,
@@ -957,6 +1001,7 @@ def __init__(
957
1001
logger .warning ("Java version checks are disabled" )
958
1002
self ._init_ap_mode (self ._profiler_state .profiling_mode , java_async_profiler_mode )
959
1003
self ._ap_safemode = java_async_profiler_safemode
1004
+ self ._ap_features = java_async_profiler_features
960
1005
self ._ap_args = java_async_profiler_args
961
1006
self ._jattach_timeout = java_jattach_timeout
962
1007
self ._ap_mcache = java_async_profiler_mcache
@@ -1214,6 +1259,7 @@ def _profile_process(self, process: Process, duration: int, spawned: bool) -> Pr
1214
1259
self ._profiler_state ,
1215
1260
self ._mode ,
1216
1261
self ._ap_safemode ,
1262
+ self ._ap_features ,
1217
1263
self ._ap_args ,
1218
1264
self ._jattach_timeout ,
1219
1265
self ._ap_mcache ,
0 commit comments