@ -9,10 +9,10 @@
//! ### Profile
//!
//! ```ignore
//! amplxe-cl -run-pass-thru=--no-altstack -v -collect hotspots target/debug/wasmtime --vtune test.wasm
//! vtune -run-pass-thru=--no-altstack -v -collect hotspots target/debug/wasmtime --vtune test.wasm
//! ```
//!
//! Note: `amplxe-cl ` is a command-line tool for VTune which must [be
//! Note: `vtune ` is a command-line tool for VTune which must [be
//! installed](https://www.intel.com/content/www/us/en/developer/tools/oneapi/vtune-profiler.html#standalone)
//! for this to work.
@ -20,10 +20,9 @@ use crate::{CompiledModule, ProfilingAgent};
use anyhow ::Result ;
use core ::ptr ;
use ittapi_rs ::* ;
use std ::collections ::HashMap ;
use std ::ffi ::CString ;
use std ::sync ::{ atomic , Mutex } ;
use wasmtime_environ ::DefinedFuncIndex ;
use wasmtime_environ ::EntityRef ;
/// Interface for driving the ittapi for VTune support
pub struct VTuneAgent {
@ -34,19 +33,13 @@ pub struct VTuneAgent {
/// Interface for driving vtune
#[ derive(Clone, Debug, Default) ]
struct State {
/// Unique identifier for the jitted function
method_id : HashMap < ( usize , DefinedFuncIndex ) , u32 > ,
}
struct State ;
impl VTuneAgent {
/// Intialize a VTuneAgent and write out the header
/// Initialize a VTuneAgent.
pub fn new ( ) -> Result < Self > {
let state = State {
method_id : HashMap ::new ( ) ,
} ;
Ok ( VTuneAgent {
state : Mutex ::new ( s tate) ,
state : Mutex ::new ( State ) ,
} )
}
}
@ -58,24 +51,15 @@ impl Drop for VTuneAgent {
}
impl State {
/// Return the unique method ID for use with the ittapi
pub fn get_method_id ( & mut self , module_id : usize , func_idx : DefinedFuncIndex ) -> u32 {
let method_id : u32 ;
unsafe {
method_id = iJIT_GetNewMethodID ( ) ;
}
assert_eq ! (
self . method_id . insert ( ( module_id , func_idx ) , method_id ) ,
None
) ;
method_id
/// Return a method ID for use with the ittapi.
fn get_method_id ( & self ) -> u32 {
unsafe { iJIT_GetNewMethodID ( ) }
}
/// Load module
pub fn event_load (
/// Notify vtune about a newly tracked code region.
fn event_load (
& mut self ,
method_id : u32 ,
filename : & str ,
module_name : & str ,
method_name : & str ,
addr : * const u8 ,
@ -94,13 +78,16 @@ impl State {
class_file_name : CString ::new ( module_name )
. expect ( "CString::new failed" )
. into_raw ( ) ,
source_file_name : CString ::new ( filename )
source_file_name : CString ::new ( "<unknown wasm filename>" )
. expect ( "CString::new failed" )
. into_raw ( ) ,
} ;
let jmethod_ptr = & mut jmethod as * mut _ as * mut _ ;
unsafe {
println ! ( "EventLoad: NotifyEvent Called {}" , method_id ) ;
log ::trace ! (
"NotifyEvent: method load (single method with id {})" ,
method_id
) ;
let _ret = iJIT_NotifyEvent (
iJIT_jvm_event_iJVM_EVENT_TYPE_METHOD_LOAD_FINISHED ,
jmethod_ptr as * mut ::std ::os ::raw ::c_void ,
@ -111,7 +98,7 @@ impl State {
/// Shutdown module
fn event_shutdown ( & mut self ) -> ( ) {
unsafe {
println ! ( "Drop was called!!!!!!\n ") ;
log ::trace ! ( "NotifyEvent shutdown (whole module) ") ;
let _ret = iJIT_NotifyEvent ( iJIT_jvm_event_iJVM_EVENT_TYPE_SHUTDOWN , ptr ::null_mut ( ) ) ;
}
}
@ -121,8 +108,11 @@ impl ProfilingAgent for VTuneAgent {
fn module_load ( & self , module : & CompiledModule , dbg_image : Option < & [ u8 ] > ) {
self . state . lock ( ) . unwrap ( ) . module_load ( module , dbg_image ) ;
}
fn trampoline_load ( & self , _file : & object ::File < '_ > ) {
// TODO: needs an implementation
fn load_single_trampoline ( & self , name : & str , addr : * const u8 , size : usize , pid : u32 , tid : u32 ) {
self . state
. lock ( )
. unwrap ( )
. load_single_trampoline ( name , addr , size , pid , tid ) ;
}
}
@ -132,29 +122,52 @@ impl State {
static MODULE_ID : atomic ::AtomicUsize = atomic ::AtomicUsize ::new ( 0 ) ;
let global_module_id = MODULE_ID . fetch_add ( 1 , atomic ::Ordering ::SeqCst ) ;
let module_name = module
. module ( )
. name
. as_ref ( )
. cloned ( )
. unwrap_or_else ( | | format ! ( "wasm_module_{}" , global_module_id ) ) ;
for ( idx , func ) in module . finished_functions ( ) {
let ( addr , len ) = unsafe { ( ( * func ) . as_ptr ( ) as * const u8 , ( * func ) . len ( ) ) } ;
let default_filename = "wasm_file" ;
let default_module_name = String ::from ( "wasm_module" ) ;
let module_name = module
. module ( )
. name
. as_ref ( )
. unwrap_or ( & default_module_name ) ;
let method_name = super ::debug_name ( module . module ( ) , idx ) ;
let method_id = self . get_method_id ( global_module_id , idx ) ;
println ! (
"Event Load: ({}) {:?}::{:?} Addr:{:?}\n" ,
method_id , module_name , method_name , addr
) ;
self . event_load (
let method_id = self . get_method_id ( ) ;
log ::trace ! (
"new function ({}) {:?}::{:?} @ {:?}\n" ,
method_id ,
default_filename ,
module_name ,
& method_name ,
addr ,
len ,
method_name ,
addr
) ;
self . event_load ( method_id , & module_name , & method_name , addr , len ) ;
}
// Note: these are the trampolines into exported functions.
for ( idx , func , len ) in module . trampolines ( ) {
let idx = idx . index ( ) ;
let ( addr , len ) = ( func as usize as * const u8 , len ) ;
let method_name = format ! ( "wasm::trampoline[{}]" , idx , ) ;
let method_id = self . get_method_id ( ) ;
log ::trace ! (
"new trampoline ({}) for exported signature {} @ {:?}\n" ,
method_id ,
idx ,
addr
) ;
self . event_load ( method_id , & module_name , & method_name , addr , len ) ;
}
}
fn load_single_trampoline (
& mut self ,
name : & str ,
addr : * const u8 ,
size : usize ,
_pid : u32 ,
_tid : u32 ,
) {
let method_id = self . get_method_id ( ) ;
self . event_load ( method_id , "wasm trampoline for Func::new" , name , addr , size ) ;
}
}